我目前正在用 C# 编写一个库,并在某些情况下使用 PowerShell 快速测试它。然而,这阻止了我重新构建项目,因为 PowerShell 显然仍然打开了 DLL。
有没有办法在用
Add-Type
添加DLL后再次卸载DLL?文档似乎没有这方面的线索,明显的候选者是 Remove-Type
(它不存在 – 无论如何只有一个命令,以 Type
作为名词)。每次我想要重建时,关闭 PowerShell 并执行导航到构建目录并再次添加类型的所有操作会变得很麻烦。
就像其他人所说,这是一种 .NET 行为。无法卸载加载到 AppDomain 中的程序集。只能卸载AppDomain,并且powershell使用单个appdomain。几年前我在博客上写过一些关于这个的文章:
当我这样测试时,我通常保持一个 shell 打开并使用嵌套 shell 来进行测试。启动 powershell,cd 到 bin 位置,然后运行“powershell”启动嵌套 shell(新进程)。“退出”重新开始,然后再次运行“powershell”。
我发现解决这个问题的最简单方法是将
Add-Type
和测试代码包装在 Start-Job
中。 Start-Job
将创建一个后台进程,并且类型将在那里加载。完成后,该过程就会消失,您可以重试。
这是它的外观示例:
$job = Start-Job -ScriptBlock {
Add-Type -path 'my.dll'
$myObj = new-object My.MyTestClassName
$result = $myObj.TestMethod
$result
}
Wait-Job $job
Receive-Job $job
测试方法的输出将回显到控制台。
如果您的程序集不需要绑定上下文,您可以这样做:
$bytes = [System.IO.File]::ReadAllBytes("Path_To_Your_Dll.dll")
[System.Reflection.Assembly]::Load($bytes)
这是一个完整的示例,允许将
Add-Type
命令作为后台作业运行,以便在完成后卸载程序集:
# Start-Job will not preserve the working directory, so do it manually
# Other arguments can also be passed to the job this way
$cd = Split-Path $MyInvocation.MyCommand.Path
$jobParams = @{
'cd' = $cd
}
Start-Job -InputObject $jobParams -ScriptBlock {
cd $Input.cd
Add-Type -Path assembly.dll
} | Receive-Job -Wait -AutoRemoveJob
Receive-Job -Wait
将确保收到作业的输出,否则它将丢失。
选中复选框:“为每个调试会话创建临时 PowerShell 扩展终端。这对于调试 PowerShell 类和二进制模块非常有用。”
这会导致每次按 F5 时都会延迟几秒钟,这很烦人。我经常通过将焦点转移到终端窗口(鼠标单击它),按向上箭头,验证命令提示符中现在是否有正确的脚本,然后按 Enter 来解决此问题。对我来说,这比等待稍微不那么烦人,但当我知道我需要一个新实例 PowerShell 时,仍然可以选择重新加载终端(按 F5)。
我也遇到过类似的问题。无法卸载类型/程序集(这是因为它适用于 .NET 框架)。
在 .NET 中,如果创建一个新的应用程序域 (
System.AppDomain
) 并将程序集加载到该域中,就可以解决这个问题。可以卸载应用程序域并卸载所有 dll。
我还没有尝试过,因为对我来说,关闭 Console 中的选项卡并打开新选项卡要简单得多。