PowerShellでGenericなクラスとかメソッドを呼び出す
昨日の記事の中でSystem.Collections.Generic.HashSet<T>というクラスを使いました。
このHashSet<T>
というクラスのコンストラクタにはICollection<T>
やIEnumerable<T>
などの配列的な値を渡すことが出来て、集合の初期値とすることが出来ます。
使い方としては以下のような感じ。
PS> [System.Collections.Generic.HashSet[String]]::new(@("alice", "bob", "alice"))
これを実行すると以下のように…エラーになります。残念。
MethodException: Cannot find an overload for "new" and the argument count: "1".
同じような感じで、HashSet<T>.UnionWith(IEnumerable<T>)的なGenericな型が使われているメソッドも呼べません。
残念ながらPowerShellでは一部のコンストラクタやメンバは提供されていないみたい…と思っていたのですが、以下のような情報を頂きました。(ありがとうございます!)
PowerShellで配列内のユニークな値の数を数える https://t.co/GdepJQ28Gb
— lu-anago (@lululu63499233) November 4, 2020
Powershellの配列からジェネリックを生成するときは[Tvalue[]]でキャストすると上手くいくというハックがあったり......
[HashSet[int]]::new([int[]]$ns).Count # これは上手くいく pic.twitter.com/2kCZwxeBEJ
エラー文は「引数が1個のnewってメソッドは無いよ」的な内容に見えるのですが、実際の意味は「引数の型が正しくない」的な意味のようです。
というわけで、引数をString[]
にキャストしてあげたら行けました。
PS> [System.Collections.Generic.HashSet[String]]::new([String[]]@("alice", "bob", "alice"))
alice
bob
ちなみに、キャストする前の配列はObject[]
だったようです。
PS> (@("alice", "bob", "alice")).GetType().Name
Object[]
PS> ([String[]]@("alice", "bob", "alice")).GetType().Name
String[]
コンストラクタだけでなく、メソッドについても同じことが言えます。
PS> $set = [System.Collections.Generic.HashSet[String]]::new()
PS> # これはダメ
PS> $set.UnionWith(@("alice", "bob"))
MethodException: Cannot find an overload for "UnionWith" and the argument count: "1".
PS> # こっちなら行ける
PS> $set.UnionWith([String[]]@("alice", "bob"))
PS> $set
alice
bob
うまく行きました。 分かれば分かるんですが、うーん…。