web-dev-qa-db-ja.com

Add-Type -TypeDefinitionでクラスがまだ追加されていない場合、条件付きでどのように追加しますか?

次の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で2回以上実行すると(たとえば、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への呼び出しをラップして、1回だけ呼び出すようにするにはどうすればよいですか?

44
Justin Dearing

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

if (-not ([System.Management.Automation.PSTypeName]'MyClass').Type)
{
    Add-Type -TypeDefinition 'public class MyClass { }'
}
  • タイプ名は、引用符「MyClass」、角括弧[MyClass]、またはその両方[[MyClass]」で囲むことができます(v3 +のみ)。
  • タイプ名の検索では、大文字と小文字は区別されません。
  • 型の完全な名前を使用する必要があります。ただし、それがシステム名前空間の一部でない場合(たとえば、[System.DateTime]は 'DateTime'で検索できますが、[System.Reflection.Assembly]は 'Assembly'で検索できません。 )。
  • これはWin8.1でのみテストしました。 PowerShell v2、v3、v4。

内部的には、PSTypeNameクラスは、重い処理を処理するLanguagePrimitives.ConvertStringToType()メソッドを呼び出します。成功すると検索文字列をキャッシュするため、追加の検索が高速になります。

X0nとJustin Dによって言及されているように、内部で例外がスローされるかどうかは確認していません。

50
skataben

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

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

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

21
LeeHolmes

これを行うにはより良い方法があります 例外の費用を負担することなく

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

pdate:まあ、とにかくpowershellは例外を除いて内部的に信号を送っています。これには悪い癖があります。インタプリタは、SEHを使用して、たとえばbreakおよびcontinueキーワードでシグナルを送信します。

18
x0n

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

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

このようにして、例外はスローされません。ロードされたアセンブリの数に基づくわずかに遅いベースです。

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