如果尚未添加具有Add-Type -TypeDefinition的类,如何有条件地添加类?

时间:2013-05-14 21:02:05

标签: powershell add-type

请考虑以下PowerShell代码段:

$csharpString = @"
using System;

public sealed class MyClass
{
    public MyClass() { }
    public override string ToString() {
        return "This is my class. There are many others " +
            "like it, but this one is mine.";
    }
}
"@
Add-Type -TypeDefinition $csharpString;
$myObject = New-Object MyClass
Write-Host $myObject.ToString();

如果我在同一个AppDomain中多次运行它(例如在powershell.exe或powershell_ise.exe中运行两次脚本),我会收到以下错误:

Add-Type : Cannot add type. The type name 'MyClass' already exists.
At line:13 char:1
+ Add-Type -TypeDefinition $csharpString;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (MyClass:String) [Add-Type],
 Exception
    + FullyQualifiedErrorId :
 TYPE_ALREADY_EXISTS,Microsoft.PowerShell.Commands.AddTypeCommand

如何将调用包装到Add-Type -TypeDefinition,以便只调用一次?

5 个答案:

答案 0 :(得分:47)

这项技术对我很有用:

if (-not ([System.Management.Automation.PSTypeName]'MyClass').Type)
{
    Add-Type -TypeDefinition 'public class MyClass { }'
}
  • 类型名称可以用引号“MyClass”,方括号[MyClass]或“[MyClass]”(仅限v3 +)括起来。
  • 类型名称查找不区分大小写。
  • 您必须使用该类型的全名,除非它是System命名空间的一部分(例如,[System.DateTime]可以通过'DateTime'查找,但是[System.Reflection.Assembly]无法通过'装配')。
  • 我只在Win8.1中测试过这个; PowerShell v2,v3,v4。

在内部,PSTypeName类调用LanguagePrimitives.ConvertStringToType()方法来处理繁重的工作。它在成功时缓存查找字符串,因此其他查找更快。

我还没有确认x0n和Justin D是否在内部抛出任何异常。

答案 1 :(得分:21)

实际上,这些都不是必需的。 Add-Type维护您提交给它的任何代码的缓存以及结果类型。如果使用相同的代码调用Add-Type两次,那么它就不会编译代码,只会从上次返回类型。

您可以通过连续两次运行Add-Type调用来验证这一点。

您在上面的示例中收到错误消息的原因是您在Add-Type调用之间更改了代码。虽然上面的解决方案在这种情况下会使错误消失,但这也意味着您正在使用可能没有按照您认为的方式运行的旧类型定义。

答案 2 :(得分:17)

有一个更好的方法来执行此操作而不会产生例外费用

if (-not ("MyClass" -as [type])) {
    add-type @"
        public class MyClass { }
"@
}

更新:好吧,显然PowerShell信号在内部有一个例外。这样做有一个坏习惯。例如,口译员使用SEH来通过breakcontinue关键字发出信号。

答案 3 :(得分:4)

最简单的方法是使用try / catch块。您有两种选择:

  • try { [MyClass] | Out-Null } catch { Add-Type -TypeDefinition $csharpString; }
  • try { Add-Type -TypeDefinition $csharpString; } catch {}

答案 4 :(得分:3)

这样就不会抛出任何异常,只是加载的程序集数量有点慢:

[bool]([appdomain]::CurrentDomain.GetAssemblies() | ? { $_.gettypes() -match 'myclass' })