次の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回だけ呼び出すようにするにはどうすればよいですか?
このテクニックは私にはうまくいきます:
if (-not ([System.Management.Automation.PSTypeName]'MyClass').Type)
{
Add-Type -TypeDefinition 'public class MyClass { }'
}
内部的には、PSTypeNameクラスは、重い処理を処理するLanguagePrimitives.ConvertStringToType()メソッドを呼び出します。成功すると検索文字列をキャッシュするため、追加の検索が高速になります。
X0nとJustin Dによって言及されているように、内部で例外がスローされるかどうかは確認していません。
実際には、これは必要ありません。 Add-Typeは、送信したすべてのコードのキャッシュと、結果のタイプを保持します。同じコードでAdd-Typeを2回呼び出すと、コードをコンパイルする手間がかからず、前回の型が返されます。
Add-Type呼び出しを続けて2回実行するだけでこれを確認できます。
上記の例でエラーメッセージが表示されたのは、Add-Typeの呼び出しの間にコードを変更したためです。上記の解決策はこの状況でそのエラーを解消しますが、それはまた、おそらくあなたが思っているように動作していないタイプの古い定義で作業していることを意味します。
これを行うにはより良い方法があります 例外の費用を負担することなく:
if (-not ("MyClass" -as [type])) {
add-type @"
public class MyClass { }
"@
}
pdate:まあ、とにかくpowershellは例外を除いて内部的に信号を送っています。これには悪い癖があります。インタプリタは、SEHを使用して、たとえばbreak
およびcontinue
キーワードでシグナルを送信します。
これを行う最も簡単な方法は、try/catchブロックです。これには2つのオプションがあります。
try { [MyClass] | Out-Null } catch { Add-Type -TypeDefinition $csharpString; }
try { Add-Type -TypeDefinition $csharpString; } catch {}
このようにして、例外はスローされません。ロードされたアセンブリの数に基づくわずかに遅いベースです。
[bool]([appdomain]::CurrentDomain.GetAssemblies() | ? { $_.gettypes() -match 'myclass' })