回答編集履歴

1 誤字(コード中の全角文字)の修正。

imihito

imihito score 2154

2019/03/26 21:37  投稿

`EventHook` の実装から、
「イベントの処理の中で`$this`と`$_`以外の任意の情報を使って処理できるようにしたい(汎用的に)」
ということだと解釈しました。
詳しく検証していませんが、以下の方法はどうでしょうか?
# 1. 「イベント登録時に」 GetNewClosure() を行う
`GetNewClosure()`は呼び出した瞬間の変数を束縛するため、スクリプトブロック実行前に呼び出してもあまり意味が無いはずです。
参考
> [powershellのクロージャを理解する - Qiita](https://qiita.com/jca02266/items/ad35844ca6fcd2103185)
```powershell
Using NameSpace System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms
$Form = [Form]::new()
$text = [TextBox]::new()
$Form.Controls.Add($text)
& {
   $abc = "abc"
   $Form.add_Click({
       
       $abc | Out-Host
   }.GetNewClosure())
}
$null -eq $abc # => $true $abc という変数は存在しない。
$Form.ShowDialog()
# => クリックすると abc が出力される
```
# 2. Register-ObjectEvent を使う
`EventHook`と似たような機構のものとして [Register-ObjectEvent](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/register-objectevent?view=powershell-6) があります。
代わりにこちらを使ってみるのはどうでしょうか?
```powershell
Using NameSpace System.Windows.Forms
Add-Type -AssemblyName System.WIndows.Forms
$Form = [Form]::new()
$text = [TextBox]::new()
$Form.Controls.Add($text)
# Register-ObjectEvent の引数が多いので、スプラッティングで指定する。
[hashtable]$regEventArgs = @{
   # イベントソースのオブジェクト及びイベント名。
   InputObject = $Form
   EventName  = 'Click'
   # $true にするとコマンドレットの返り値を無くし、Get-EventSubscriber や Unregister-Event からイベントを隠蔽する。
   # $true にしたときはGet-EventSubscriber -Force | Unregister-Event -Force など -Force スイッチをつけることで取得・削除が可能。
   SupportEvent = $false
   
   # 任意の情報を指定。
   MessageData = @('任意の引数', [datetime]::Now)
   Action = {
       Write-Host "Block : $($sender.Gettype().Name)"
       
       # 任意の情報の確認。
       $event.MessageData | Out-Host
       # Register-ObjectEvent の Action 内専用の自動変数。
       # $event, $eventSubscriber, $sender, $eventArgs, $args
       # $sender   は $this 相当。
       # $eventArgs は $_ 相当。
       # $args     は $this, $_ 相当。
       # 自動変数の中身確認用。
       Get-Variable -Name event, eventSubscriber <#, sender, eventArgs, args#> |
           ForEach-Object -Process {
               $_.Name
               $_.Value
           } | Out-Host
           } #| Out-Host
       
   }
}
Register-ObjectEvent @regEventArgs
$Form.ShowDialog()
```

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る