2013-05-14 10 views
31

は、次のPowerShellがスニペット考えてみましょう:Add-Type -TypeDefinitionが既に追加されていない場合、クラスを条件付きで追加するにはどうすればよいですか?

$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(); 

私は(たとえばた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への呼び出しを1回だけ呼び出すようにするにはどうすればよいですか?

答えて

34

この技術は私に適しています:

if (-not ([System.Management.Automation.PSTypeName]'MyClass').Type) 
{ 
    Add-Type -TypeDefinition 'public class MyClass { }' 
} 
  • 型名ことができます引用符 "MyClass"、角括弧[MyClass]、または両方の[MyClass](v3 +のみ)で囲む必要があります。
  • タイプ名検索では、大文字と小文字は区別されません。
  • システムネームスペースの一部でない限り、タイプのフルネームを使用する必要があります([System.DateTime]は 'DateTime'で検索できますが[System.Reflection.Assembly]は参照できません) 'アセンブリ')。
  • 私はこれをWin8.1でのみテストしました。 PowerShell v2、v3、v4

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

私はX0NとジャスティンD.実は、これのどれもが必要とされない

+0

それは本当に素晴らしいです! CLR例外はスローされません。 –

3

これを実行する最も簡単な方法はtry/catchブロックです。

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

第2の方法は、あなたが知りたいかもしれない他のエラーを隠すでしょう – as9876

13

例外のコストをかけずに、この を行うためのよりよい方法はあり:あなたはこれを行うための2つのオプションがあり

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

更新:よく、明らかにpowershell信号は内部的にとにかく例外があります。これには習慣がありません。インタプリタはSEHを使用して、例えばbreakcontinueキーワードで通知します。

+2

これは実際に例外を引き起こします。私はpowershell.exeをWinDbgに接続し、 '' MyCladdss 'を実行すると、 ''私は ''(1e04.2424):CLR例外 - コードe0434352(最初のチャンス) 'を得る。だから、明示的に私のコードでtry/catchをしているわけではありませんが、CLRはあります。 –

+0

例外は何ですか?あなたはもっと見ましたか? – x0n

+0

それは 'Automation.PSInvalidCastException'メッセージでした:*" System.TString "タイプに" System.String "タイプの" MyCladdss "値を変換できません。 InnerExceptionはありません。おそらく、私はWindows Internalsの詳細を知らないのですが、CLR例外がStructured Exception Handler(SEH)を呼び出してCPU例外を呼び出すことはないので、同様のパフォーマンスの問題がありますか?私が気付いていない何かが例外の問題を特定するか? –

3

例外がスローされない。この方法で、それがロードされたアセンブリの数にほんの少し遅いベースです:

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

アセンブリ上の空の「場所」を確認すると、これをスピードアップできます。 – Droj

16

で述べたように、例外が内部的にスローされるかどうかを確認していません。 Add-Typeは、結果として得られた型と共に、それに提出するコードのキャッシュを保持します。同じコードでAdd-Typeを2回呼び出すと、コードのコンパイルに気を使わず、前回のタイプから返されます。

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

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

+0

私が質問を書くとき、私はそれを呼び出すPowerShell以上にコンパイルしていたC#コードを編集していました。これを反映するために質問を編集します。これは、しかし、動作を説明するのに役立ちます。それを指摘してくれてありがとう。 –

+0

C#の編集が正しいことを確認していたのはどうでしたか?このマニュアル「定義されていない場合は...」を使用すると、Add-Typeはあなたのコードを決して見ません。 – LeeHolmes

+0

あなたはそうです。私は正確に覚えていない。私は正しい動作を今すぐ理解してうれしいです。 –

関連する問題