以下の内容はhttps://tech.guitarrapc.com/entry/2013/03/20/170321より取得しました。


PowerShellでHashtableを型付けしたい

どうも、動的型付なPowerShellです。 といっても型好きなPowerShellerです。

ということで、だれもがイラッとする型安全ではない(type-unsafe) Hashtableを型安全(type-safe)にできないかというのが今回の記事です。

Hashtableとは

ようは連想配列ですね。

MSDN - Hashtable クラス.aspx)

基本的な使い方はHey, Scripting Guy! 様にお出まし願います。

Hey, Scripting Guy! Blog // Easily Create a PowerShell Hash Table

さて、今回の狙いはこのHashtableのName.Valueを型制約できないかという事を試します。

通常のHashtable

例えば以下のHashtable $employeeを考えます。

  • KeysがNO、Valueが123456
  • KeysがName、ValueがAlice

これを作るには、@{K=V}や@{}の.Key=ValueとHashtableのプロパティ指定で作成するのが一般的でしょう。

# Week Typed Hash Table
PS> $emploee = @{}
PS> $emploee.NO = 123456
PS> $emploee.Name = "Alice"
PS> $emploee
Name  : Name
Value : Alice

Name  : NO
Value : 123456

PSCustomObjectにキャストすれば他のオブジェクト同様に使いやすくなりますね

Name      NO
----      --
Alice 123456

通常のHashtableは型安全ではない(type-unsafe)

先ほど、"Alise"としたValueの型を見てみると、

$emploee.Name.GetType().FullName

string型になっています。

System.String

では、作った$employee{}.NameキーのValueに数値を入れてみましょう。

$emploee.Name = 456

動的型付けにより、型変換エラーなく入ってます。出力してみましょう。

PS> $emploee
Key   : NO
Value : 123456

PS> [PSCustomObject]$emploee | Format-Table -AutoSize
NO Name
--  ----
123456  456

NameキーのValueの型を調べるとint型になっていますね

PS> $emploee.Name.GetType().FullName
System.Int32

このようにPowerShellの@{K=V}で作成したHashtableは、型制限がなく動的に型変換されます。

Hashtableを型制約して型安全(type-safe)にする

Hashtableは、System.Collections.Hashtableを生成しているわけです。 つまり、このコードでも@{}と同等のHashtableが生成されます。

$hash = @{}
$hashDotNet = New-Object 'System.Collections.Hashtable' #hashと一緒

ならば、作成時に、K,Vそれぞれの型を制約すればいいわけです。そこで、GenericなDictionaryを使います。 イメージ的にはこうです。

System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

Dictionaryを作ってK,Vに値を入れてみましょう。

$emploeeTyped = New-Object 'System.Collections.Generic.Dictionary[string, int]'
$emploeeTyped.NO = 123456

エラーなく上手く入ったようですので確認します。

PS> $emploeeTyped
Key   : NO
Value : 123456

では、Vに文字列を入れてみます。int型にはstring型を入れられませんと、きっちりはじいてくれました。

PS> $emploeeTyped.Name = "Margaret""Margaret" を型 "System.Int32" に変換できません。エラー: "入力文字列の形式が正しくありません。"
発生場所 D:\Document\Program\Powershell\TypedHashtable\TypedHashtable.ps1:17 文字:1
+ $emploeeTyped.Name = "Margaret"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) []、RuntimeException
    + FullyQualifiedErrorId : InvalidCastFromStringToInteger

当然、NoのK,Vしか入っていません。

PS> $emploeeTyped
Key   : NO
Value : 123456

例えDisctionaryにしても,[PSCustomObject]へのキャストはできるので安心です。

PS> [PSCustomObject]$emploeeTyped
Key  Value
---  -----
NO  123456

まとめ

これで、Hashtableが型安全(type-safe)に生成できます。

PSCustomObjectという便利なオブジェクト生成手段に利用するため、HashtableというよりDictionaryにして使い勝手を管理できると嬉しいですね。

ただ、PowerShellは動的型付なのでHashTableでも型エラーがでないので気にされにくいのでしょうか…今更ネタかなぁ…。

補足

LINQ星人の指摘で、Hashtableのクラス間違えていたので修正しました。




以上の内容はhttps://tech.guitarrapc.com/entry/2013/03/20/170321より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14