PowerShell といえば、型です。
文字列じゃなくて型。ということは、インテリセンスが何を使えるか教えてくれるわけです。インテリセンス使えないと辛いですよね。
自作の関数を作ったことがある人は多いと思います。でも、作った関数の出力結果がパイプラインの先でインテリセンス効かないって経験ありませんか?
今回はどうしてなのか、どうやって解決するのかを説明します。
目次
問題はどういうこと
例えば、[System.String]
を返すだけの単純な関数を考えてみます。
ではこの関数を実行した結果を、パイプラインの先に伝搬してみましょう。
結果は?自動変数$_
で.
ピリオドを入力してもインテリセンスがききません。しょぼーん。
つまり、さくっと関数を書いても、パイプラインの先にオブジェクトが渡るまで型をインテリセンスでサポートしてくれないわけです。
出力型を明示する
これは C# でCmdlet を書いていると気づきません。C# なら返戻値の型を明示するからです。
しかし、PowerShell スクリプトで関数を書いていると逆に返戻値の型を明示することを失念しがちです。そう、返戻値の型を明示してインテリセンスを助けてないから、パイプラインの先で型がわからないのです。
対応方法
高度な関数(でしたっけ? Advanced Function とか言われたりする奴ですね) の中に答えがあります。
返戻値の型を明示するには、[OutputType()]
属性を付ければ ok です。*1*2
コードで示しましょう。
これで先ほどと同様にパイプラインの先に型が伝搬したかみてみると?
自動変数$_
の後に ピリオド.
を入力した瞬間、うまく型がインテリセンスに表示されましたね。
[OutputType()]
属性のいけてなさ
意味があったのに余り使われていないのには、知られてないノか欠点が目立ってるからなのか。
いけてないところを見てみます。
返戻値の型がずれても何も警告もエラーも出ない
C# なら、返戻値の型と実際の型がずれることはVSで警告を出して起こることがないですね。
しかし、PowerShell ISE というか、PowerShell のインテリセンスは賢くないのでそんなことしてくれません。当然キャストもしません。
ということは、返戻値の型 と [OutputType()]
で示した他型がずれることがふつーにざらにありえます。
例えばこう。
[OutputType()]
は System.Int32
を示したにも関わらず、実際の返戻値は System.Uri
型です。
パイプラインで渡してインテリセンスを見てみると?System.Int32
の型がインテリセンスで表示されました。実際の型とずれていますね。
nyao | %{$_ | Get-Member} TypeName: System.Uri Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object comparand) GetComponents Method string GetComponents(System.UriComponents components, System.UriFormat f... GetHashCode Method int GetHashCode() GetLeftPart Method string GetLeftPart(System.UriPartial part) GetObjectData Method void ISerializable.GetObjectData(System.Runtime.Serialization.Serializat... GetType Method type GetType() IsBaseOf Method bool IsBaseOf(uri uri) IsWellFormedOriginalString Method bool IsWellFormedOriginalString() MakeRelative Method string MakeRelative(uri toUri) MakeRelativeUri Method uri MakeRelativeUri(uri uri) ToString Method string ToString() AbsolutePath Property string AbsolutePath {get;} AbsoluteUri Property string AbsoluteUri {get;} Authority Property string Authority {get;} DnsSafeHost Property string DnsSafeHost {get;} Fragment Property string Fragment {get;} Host Property string Host {get;} HostNameType Property System.UriHostNameType HostNameType {get;} IsAbsoluteUri Property bool IsAbsoluteUri {get;} IsDefaultPort Property bool IsDefaultPort {get;} IsFile Property bool IsFile {get;} IsLoopback Property bool IsLoopback {get;} IsUnc Property bool IsUnc {get;} LocalPath Property string LocalPath {get;} OriginalString Property string OriginalString {get;} PathAndQuery Property string PathAndQuery {get;} Port Property int Port {get;} Query Property string Query {get;} Scheme Property string Scheme {get;} Segments Property string[] Segments {get;} UserEscaped Property bool UserEscaped {get;} UserInfo Property string UserInfo {get;}
なんだこれ。厄介としか言いようがありません。警告してくだされ~。
PSCustomObject
の厄介さ
PowerShell を使っていて PSCustomObject
を触ったことがない人は、v2 の人ですね?お疲れ様です。
PSCustomObject
は、いろんな意味で PowerShell らしいともいえる、便利だけど特殊な型です。PSCustomObject
を使うと任意のプロパティを含んだオブジェクトがさくっと、低コスト、便利に作れるので多用することが多いでしょう。
しかし、任意のプロパティを自在に含められるため、インテリセンスと相性はさいてーです。サイテー。
たとえば、次のような関数をパイプラインの先で補完してみても?
当然ですが、piyo
プロパティはインテリセンスに出ませんね。
まとめ
[OutputType()]
大事ですよ?使ってなかった人はぜひ使ってください。
型大事です。実際。もぅ、yield return
用意したりして、[Void]
以外はreturn
必須にしたり、[OutputType()]
と検査すればいいのにって思っちゃいますね。