タグ別アーカイブ: コンテスト

Windows PowerShell Get-Enjoy コンテスト

昨年末、マイクロソフト主催の「Windows PowerShell Get-Enjoy コンテスト」というコンテストにスクリプトを応募しました。「Windows PowerShell」の名を冠しながら「Windows PowerShell で作成されたスクリプトである必要はありません。」と銘打たれている変わったコンテストでしたが、評価が不当に低い気がする PowerShell が、このようなイベントを通じて認知されていけば嬉しいことです。便利な PowerShell ですが、今よりユーザーが増えればもっともっと便利になるでしょう。

応募したスクリプトは、「Windows PowerShell で delegate」で掲載したスクリプト「New-Delegate.ps1」です。ありがたいことに吉岡洋様より選考委員特別賞をいただきました。賞品のデジタルビデオが届くのを楽しみに待っています。


Windows PowerShell で delegate

New-Delegate.ps1 は、スクリプトブロックからデリゲートを作るスクリプトです。

用例1: 3 秒後に音が鳴ります。

PS> $delegate = New-Delegate Threading.ThreadStart {Start-Sleep 3; [Media.SystemSounds]::Beep.Play()}
PS> $thread = New-Object Threading.Thread ($delegate)
PS> $thread.Start()

用例2: System.Collections.Generic.List<int> を逆順にソートします。

PS> $list = New-Object Collections.Generic.List``1[System.Int32]
PS> $list.AddRange([int[]](1..3))
PS> $list
1
2
3
PS> $delegate = New-Delegate Comparison``1[System.Int32] {$args[1] - $args[0]}
PS> $list.Sort($delegate)
PS> $list
3
2
1

ご覧のように、第一引数にデリゲート型を、第二引数にスクリプトブロックを指定して呼び出すと、その型のデリゲートを作成し、デリゲートが呼び出された際にスクリプトブロックを実行します。

用例2 のように、デリゲートのパラメータは $args に代入され、スクリプトブロックの出力はデリゲートの戻り値となります。

実装

ソース中で IL を出力しているために、大変読みにくくなっていますが、原理は単純です。

ArrayList に、実行環境となる Runspace と、実行すべき ScriptBlock を格納し、そのArrayList に System.Reflection.Emit.DynamicMethod による新たな動的メソッドを作成してバインドします。

動的メソッド内部では、与えられたパラメータを指定してスクリプトブロックを実行し、その出力をキャストして戻り値に代入しています。

PowerScript は、手軽にコマンドを実行できるシェルであると同時に、非常に強力なスクリプト環境であることは異論がないでしょう。 .NET Framework のオブジェクトをそのまま使用できることが、その強力なパワーの源となっています。 .NET Framework を使えば、プログラムからコンパイルもできます。アセンブルもできます。

つまり、PowerShell にデリゲートを作る手段が無ければ、その手段を作ってしまえば良いのです。

追記

2008年4月17日追記:
このスクリプトは、Windows PowerShell Get-Enjoy コンテストにて選考委員特別賞を受賞しました。