💪
PowerShellで拡張メソッドを書きたかったけど、それってValueFromPipelineで済むのでは?と気づいてのアレコレ。
発端
C#に慣れ親しんでいるPowerShell使いは、稀に拡張メソッドを生やしたくなる。
先駆者様
しかし、最近PowerShellでデータ加工するモジュールを作っていて気づいた。
これ、ValueFromPipelineで済むのでは?
と思っていろいろ試してみた。
さくっと
例えば文字列に関する拡張メソッドを生やしたいとき、下記のような関数を作ればそれっぽいことができる。
function ReplaceAtoa {
param (
[Parameter(ValueFromPipeline)][string]$text
)
return $text -replace "A","a"
}
"GAFA, GAFA !" | ReplaceAtoa
List[int]に生やしたい時、直感的に書くと下記になりそう。
function PlusOne {
param (
[Parameter(ValueFromPipeline)][System.Collections.Generic.List[int]]$_input
)
return $_input | % { $_ + 1 }
}
(1..5) | PlusOne
だが、これは思った挙動にならない。
PowerShell的なコードはこんな感じ↓(他にも最適なコードがあるはず)。
function PlusOne {
param (
[Parameter(ValueFromPipeline)][int]$_input
)
process{
return $_ + 1
}
}
[System.Collections.Generic.List[int]](1..5) | PlusOne
じゃあフィルタ(Whereみたいなやつ)が作りたいときはどうするのか。
不要なreturnをしなければいい。
function WhereEven {
param (
[Parameter(ValueFromPipeline)][int]$_input
)
process{
if ($_input % 2 -eq 0) { return $_ };
}
}
[System.Collections.Generic.List[int]](1..5) | WhereEven
終わりに
ValueFromPipelineでやりたかったことは代替できそう。
ただ、独自のインターフェース型を定義して~みたいな使い方は、PowerShell自体ではinterfaceの定義ができないので現状はC#で迂回策をとったりする必要がある。
まぁValueFromPipelineByPropertyNameでそれっぽいバリデーションチックなことができるけれど、個人的には[Parameter(ValueFromPipeline)][IPerson]$person
みたいな感じで書きたいよねという気持ちはあるのでいつかインターフェースの定義ができるようになって欲しい。
質問とか、他にも有益そうな知見があればコメントください。
Discussion