如何让 PowerShell 添加类型使用添加类型
我正在开发一个 PoSh 项目,该项目生成 CSharp 代码,然后将其添加到内存中。
新类型使用磁盘 DLL 中的现有类型,该 DLL 通过 Add-Type 加载。
一切都很好,直到我真正尝试调用新类型的方法。这是我正在做的一个示例:
$PWD = "."
rm -Force $PWD\TestClassOne*
$code = "
namespace TEST{
public class TestClassOne
{
public int DoNothing()
{
return 1;
}
}
}"
$code | Out-File tcone.cs
Add-Type -OutputAssembly $PWD\TestClassOne.dll -OutputType Library -Path $PWD\tcone.cs
Add-Type -Path $PWD\TestClassOne.dll
$a = New-Object TEST.TestClassOne
"Using TestClassOne"
$a.DoNothing()
"Compiling TestClassTwo"
Add-Type -Language CSharpVersion3 -TypeDefinition "
namespace TEST{
public class TestClassTwo
{
public int CallTestClassOne()
{
var a = new TEST.TestClassOne();
return a.DoNothing();
}
}
}" -ReferencedAssemblies $PWD\TestClassOne.dll
"OK"
$b = New-Object TEST.TestClassTwo
"Using TestClassTwo"
$b.CallTestClassOne()
运行上面的脚本在最后一行给出以下错误:
使用“0”参数调用“CallTestClassOne”时出现异常: “无法加载文件或程序集“TestClassOne,...” 或其依赖项之一。系统找不到指定的文件。” 在 AddTypeTest.ps1:39 字符:20 + $b.CallTestClassOne <<<<< () + 类别信息: 未指定: (:) [], MethodInitationException + FullQualifiedErrorId :DotNetMethodException
我做错了什么?
I'm working on a PoSh project that generates CSharp code, and then Add-Type
s it into memory.
The new types use existing types in an on disk DLL, which is loaded via Add-Type.
All is well and good untill I actualy try to invoke methods on the new types. Here's an example of what I'm doing:
$PWD = "."
rm -Force $PWD\TestClassOne*
$code = "
namespace TEST{
public class TestClassOne
{
public int DoNothing()
{
return 1;
}
}
}"
$code | Out-File tcone.cs
Add-Type -OutputAssembly $PWD\TestClassOne.dll -OutputType Library -Path $PWD\tcone.cs
Add-Type -Path $PWD\TestClassOne.dll
$a = New-Object TEST.TestClassOne
"Using TestClassOne"
$a.DoNothing()
"Compiling TestClassTwo"
Add-Type -Language CSharpVersion3 -TypeDefinition "
namespace TEST{
public class TestClassTwo
{
public int CallTestClassOne()
{
var a = new TEST.TestClassOne();
return a.DoNothing();
}
}
}" -ReferencedAssemblies $PWD\TestClassOne.dll
"OK"
$b = New-Object TEST.TestClassTwo
"Using TestClassTwo"
$b.CallTestClassOne()
Running the above script gives the following error on the last line:
Exception calling "CallTestClassOne" with "0" argument(s):
"Could not load file or assembly 'TestClassOne,...'
or one of its dependencies. The system cannot find the file specified."
At AddTypeTest.ps1:39 char:20
+ $b.CallTestClassOne <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
What am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
发生这种情况是因为 CLR 加载程序会在应用程序(PowerShell 的)基目录中查找任何程序集。当然,它在那里找不到你的程序集。解决此问题的最佳方法是像 stej 提到的那样挂钩 AssemblyResolve 事件,但使用它来告诉 CLR 程序集在哪里。您无法使用 PowerShell 2.0 的 Register-ObjectEvent 来执行此操作,因为它不适用于需要返回值(即程序集)的事件。在这种情况下,让我们通过 Add-Type 使用更多 C# 来为我们完成这项工作。这段代码的工作原理是:
This happens because any assemblies are looked for by the CLR loader in the application's (PowerShell's) base directory. Of course, it doesn't find your assembly there. The best way to solve this is to hook the AssemblyResolve event as stej mentions but use it to tell the CLR where the assembly is. You can't do this with PowerShell 2.0's Register-ObjectEvent because it doesn't work with events that require a return value (ie the assembly). In this case, let's use more C# via Add-Type to do this work for us. This snippet of code works:
当您将
TestClassTwo
输出到 dll(与TestClassOne
位于同一目录中)并Add-Type
时,它就可以工作。或者至少在我的机器上;)所以这就是丑陋的解决方法。当调用 $b.CallTestClassOne() 时,PowerShell 尝试(出于某种我不知道的原因)在这些位置查找程序集 TestClassOne.dll:
这是 fuslogvw 工具的输出。它可能对你有用。使用 ProcessMonitor 可以实时看到相同的路径列表。
您也可以尝试这个(在调用
CallTestClassOne()
之前),这将向您显示哪些程序集失败了以及更多信息。
我同意它应该按您的预期工作。这就是为什么这看起来有些错误。
When you output the
TestClassTwo
to a dll (in the same directory asTestClassOne
) andAdd-Type
it, it works. Or at least at my machine ;) So that's the ugly workaround.When calling
$b.CallTestClassOne()
PowerShell tries (from some reason I don't know) to find assembly TestClassOne.dll at these locations:This is output from fuslogvw tool. It might be useful for you. The same list of paths can bee seen live using ProcessMonitor.
You might also try this (before calling
CallTestClassOne()
This will show you what assembly failed and some more info.
I agree that it should work as you expect. So that's why this looks somewhat buggy.