50

次の 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 でスクリプトを 2 回実行すると)、次のエラーが発生します。

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への呼び出しをラップして、一度だけ呼び出されるようにするにはどうすればよいですか?

4

5 に答える 5

56

このテクニックは私にとってうまくいきます:

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] は 'Assembly' で検索できません)。 )。
  • これは Win8.1 でのみテストしました。PowerShell v2、v3、v4。

内部的には、PSTypeName クラスは、面倒な作業を処理する LanguagePrimitives.ConvertStringToType() メソッドを呼び出します。成功するとルックアップ文字列がキャッシュされるため、追加のルックアップが高速になります。

x0n と Justin D が述べたように、内部で例外がスローされるかどうかは確認していません。

于 2014-03-03T20:34:49.723 に答える
24

実際には、これは必要ありません。Add-Type は、結果の型と共に、送信したコードのキャッシュを保持します。同じコードで Add-Type を 2 回呼び出すと、コードをコンパイルする手間がかからず、前回の型が返されます。

Add-Type 呼び出しを 2 回続けて実行するだけで、これを確認できます。

上記の例でエラー メッセージが表示された理由は、Add-Type の呼び出しの間にコードを変更したためです。上記の解決策により、この状況でそのエラーが解消されますが、それはまた、おそらくあなたが思っているように動作していないタイプの古い定義で作業していることを意味します.

于 2014-03-03T23:42:55.843 に答える
4

この方法では例外はスローされません。ロードされたアセンブリの数に基づいて少し遅いだけです。

[bool]([appdomain]::CurrentDomain.GetAssemblies() | ? { $_.gettypes() -match 'myclass' })
于 2013-05-15T12:40:05.007 に答える
4

これを行う最も簡単な方法は、try/catch ブロックです。これを行うには、次の 2 つのオプションがあります。

  • try { [MyClass] | Out-Null } catch { Add-Type -TypeDefinition $csharpString; }
  • try { Add-Type -TypeDefinition $csharpString; } catch {}
于 2013-05-14T21:02:04.543 に答える