您可以再次在PowerShell中删除Add-ed Type吗?

时间:2010-07-30 08:06:07

标签: dll powershell add-type

我目前正在用C#编写一个库,并且在某些情况下使用PowerShell快速测试它。但是,这阻止我重新构建项目,因为PowerShell显然仍然打开DLL。

有没有办法在用Add-Type添加DLL后再次卸载DLL?文档似乎没有线索,明显的候选人将是Remove-Type(不存在 - 只有一个命令,Type作为名词)。关闭PowerShell并执行导航到构建目录的所有内容并在每次要重建时再次添加类型都很麻烦。

7 个答案:

答案 0 :(得分:53)

与其他人一样,这是一种.NET行为。无法卸载加载到AppDomain中的程序集。只能卸载AppDomain,而powershell使用单个appdomain。几年前我在博客上写了一些文章:http://www.nivot.org/2007/12/07/WhyAppDomainsAreNotAMagicBullet.aspx

当我像这样测试时,我通常会打开一个shell并使用嵌套的shell来进行测试。启动powershell,cd到bin位置然后运行“powershell”以启动嵌套shell(新进程。)“exit”重新开始,然后再次运行“powershell”。

答案 1 :(得分:35)

我发现解决此问题的最简单方法是将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

测试方法的输出将回显到控制台。

答案 2 :(得分:22)

如果你的程序集不需要binding context,你可以这样做:

$bytes = [System.IO.File]::ReadAllBytes("Path_To_Your_Dll.dll")
[System.Reflection.Assembly]::Load($bytes)

答案 3 :(得分:3)

这是一个完整的示例,允许将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将确保收到作业的输出,否则会丢失。

答案 4 :(得分:1)

Adam Furanek的blog具有最简单,最好的解决方法。如下所示。如果您想了解如何传递参数,可以在https://samtran.me/2020/02/09/execute-c-code-with-parameters-using-powershell/

处看到。
$id = get-random
$code = @"
using System;
namespace HelloWorld
{
    public class Program$id
    {
        public static void Main(){
            Console.WriteLine("Hello world again!");
        }
    }
}
"@

Add-Type -TypeDefinition $code -Language CSharp 
Invoke-Expression "[HelloWorld.Program$id]::Main()"

答案 5 :(得分:0)

我一直面临类似的问题。无法卸载类型/程序集(因为它适用于.NET框架)。

在.NET中,如果您创建一个新的应用程序域(System.AppDomain)并将程序集加载到该域中,则可以解决该问题。可以卸载app域并卸载所有dll。

我还没有尝试过,因为对我而言,关闭Console中的标签并打开新标签要简单得多。

答案 6 :(得分:0)

此问题有一个简单的解决方法。只需在类名中添加随机后缀即可。

$id = get-random
$code = @"
using System;
namespace HelloWorld    {
    public class Program$id
{
    public static void Main(){
        Console.WriteLine("Hello world!");
    }
}
}"@

Add-Type -TypeDefinition $code -Language CSharp 
iex "[HelloWorld.Program$id]::Main()"

(来自:使用 PowerShell 脚本执行 C# 代码——随机 IT 工具 https://blog.adamfurmanek.pl/2016/03/19/executing-c-code-using-powershell-script