以下代码创建一个内存类型,找到其程序集,然后尝试添加引用第一个类型的另一个类型:
Add-Type -TypeDefinition 'namespace MyNamespace { public class c {}}'
$assembly =
$([System.AppDomain]::CurrentDomain.
GetAssemblies().
GetTypes() |
? {$_.Namespace -eq 'MyNamespace' } |
% Assembly |
Select-Object -Unique -First 1 )
Add-Type -TypeDefinition 'namespace MyNamespace {public class d : c {}}' `
-ReferencedAssemblies $assembly
尝试失败并出现错误
Add-Type: C:\repro.ps1:12
Line |
12 | Add-Type -TypeDefinition 'namespace MyNamespace {public class d : c { …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| The value cannot be an empty string. (Parameter 'path')
这表明Add-Type
正在寻找一条可能不存在的路径,因为程序集只存在于内存中。
是否可以添加引用仅内存类型的类型?
什么有效
以下方法有效,但要求程序集存在于文件系统中:
Remove-Item .\c.dll,.\d.dll -ErrorAction SilentlyContinue
Add-Type `
-TypeDefinition 'namespace MyNamespace { public class c {}}' `
-OutputAssembly .\c.dll
Add-Type -Path .\c.dll
[MyNamespace.c]::new()
Add-Type -TypeDefinition 'namespace MyNamespace {public class d : c {}}' `
-ReferencedAssemblies .\c.dll `
-OutputAssembly .\d.dll
Add-Type -Path .\d.dll
[MyNamespace.d]::new()
答案已由您在问题中的发现所暗示,但请让我详细说明一下:
从PowerShell (Core) 7 v7.4.x 开始:
事实上,虽然
Add-Type
的-ReferencedAssemblies
参数 确实接受实例(在绑定到 -typed 参数的上下文中将[System.Reflection.Assembly]
其字符串化为其属性)(作为传递程序集文件路径的替代方法),但只有当它们代表磁盘上的程序集时才会识别这些实例,即,其属性报告文件系统路径的实例。.FullName
[string[]]
.Location
由于在没有参数的情况下
Add-Type -TypeDefinition
调用会产生内存中的程序集,因此此类程序集不能在以后的调用-OutputAssembly
中用作参数。-ReferencedAssemblies
Add-Type
看起来这个限制(目前没有记录)是由 PowerShell施加的,而不是由实现 C# 编译器的底层 .NET 类型施加的,后者在 PowerShell 的进程内调用。[1]
因此,可以想象, PowerShell 7 的未来版本将取消这一限制 - 这取决于是否有人站出来在GitHub 存储库中提交相关问题
因此,目前的解决方案确实是为以后调用中必须引用的类型创建磁盘
Add-Type
程序集:这样做很麻烦:
Add-Type
如果传递的目标文件已经存在(没有开关),则必然会失败。-OutputAssembly
-Force
虽然
-PassThru
在使用时通常需要使用开关-OutputAssembly
以便将生成的磁盘程序集加载到当前会话中,但令人费解的是,还需要确保稍后Add-Type
使用在磁盘程序集上构建的内存-ReferencedAssemblies
程序集的调用实际上在当前会话中显示生成的内存程序集类型。在Windows上,您无法确保在退出会话时删除磁盘上的程序集,因为它仍然被锁定(在类 Unix 环境中工作正常)。
[1] 实现 C# 编译器的类型是
Microsoft.CodeAnalysis.CSharp.CSharpCompilation
,其.Create()
方法的references
参数需要Microsoft.CodeAnalysis.MetadataReference
实例,这些实例可以从内存中的程序集中获取,例如通过此构造函数重载。