在函数中使用“Add-Type”。内存泄漏?

时间:2017-04-04 22:24:59

标签: c# .net powershell

如果调用Add-Type函数在函数中添加一段C#代码,那么一旦函数执行完毕,“type”会被垃圾收集吗?或者该类型是否仍然存在于内存中,因为它是加载到AppDomain中的(虚拟)程序集的一部分? (因此是“内存泄漏”)

在下面的Lock-WorkStation定义中,Add-Type用于添加用C#编写的代码:

function Lock-WorkStation {
    $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@

    $name = "Win32LockWorkStation"
    $LockWorkStation = Add-Type -MemberDefinition $signature -Name $name -Namespace Win32Functions -PassThru
    $LockWorkStation::LockWorkStation() | Out-Null
}

我的问题是,如果这个函数被称为多个类型,那么它会不断地解析并添加C#代码作为(虚拟)程序集。 (或者是垃圾收集?)

将它写成:

更好吗?
Function Lock-WorkStation {
    if (!$Global:LockWorkStation) {
        $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
        $name = "Win32LockWorkStation"
        $global:LockWorkStation = Add-Type -MemberDefinition $signature -Name $name -Namespace Win32Functions -PassThru
    }

    $global:LockWorkStation::LockWorkStation() | Out-Null
}

这样C#代码只被实例化为程序集一次?

2 个答案:

答案 0 :(得分:1)

测试结果类型是否已存在:

function Lock-WorkStation {
    $name = 'Win32LockWorkStation'
    $namespace = 'Win32Functions'
    $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
    if(-not ($LockWorkStation = "$namespace.$name" -as [type])){
        $LockWorkStation = Add-Type -MemberDefinition $signature -Name $name -Namespace $namespace -PassThru
    }
    $LockWorkStation::LockWorkStation() | Out-Null
}

答案 1 :(得分:1)

谢谢Mathias的回答。然而,我的问题是关于调用Add-Type每次调用时是否实例化类型。我查看了文档,其中说:

  

会话中的类型名称和命名空间必须为唯一。您无法卸载类型或更改它。如果需要更改类型的代码,则必须更改名称或启动新的Windows PowerShell会话。否则,命令失败。 (Add-Type Documentation)

Add-Type将在第一次调用时实例化该类型。在具有相同参数的后续调用中,因为该类型已存在,所以它将不执行任何操作。因此,在if语句中包含Add-Type条件的唯一原因是出于效率原因,因为调用Add-Type会产生检查类型是否已存在的开销。

您的if条件:

-not ($LockWorkStation = "$namespace.$name" -as [type])

恕我直言,效率不高,因为它使用字符串插值来计算类型名称,然后检查类型是否存在,然后每次运行时都将类型分配给变量。

相反,您可以设置一次类型变量(范围为Script:)。 if语句可以检查它是否为null,如果是,则实例化它:

function Lock-WorkStation {
    if ($Script:Win32LockWorkStation -eq $null) {
        $namespace = 'Win32Functions'
        $name = 'Win32LockWorkStation'

        $signature = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
'@
        $Script:Win32LockWorkStation = Add-Type -Namespace $namespace -Name $name -MemberDefinition $signature -PassThru
    }

    $Script:Win32LockWorkStation::LockWorkStation() | Out-Null
}

如果您愿意,可以查看performance comparison在函数中使用Add-Type的不同方法。