92310


[こちらの質問](https://ja.stackoverflow.com/questions/92305/powershell%E3%81%AE%E9%80%A3%E6%83%B3%E9%85%8D%E5%88%97%E3%82%92%E9%96%A2%E6%95%B0%E3%81%AE%E6%88%BB%E3%82%8A%E5%80%A4%E3%81%A8%E3%81%97%E3%81%A6%E8%BF%94%E3%81%9B%E3%81%AA%E3%81%84)の追加質問となります。その際、回答のあったコードは以下となります。

[code]

    # 連想配列作成
    Function makeHashTable{
        Param(
            param1,
            param2
        )
        for($iをインデックス番号でまわす){
            $value = @()
            foreach($v in $values){
                $str = 略
                $value += $str
            }
            $HashTable.Add($List[$i], $value)
        }
    }
    
    # ボタン2の処理
    Function Calc{
        $HashTableを使った処理
    }
    
    略
    
    # ここで連想配列を作成する
    $HashTable = [System.Collections.Generic.Dictionary[String, PSObject]]::new()
    
    # 連想配列作成ボタン
    $Button1 = 略
    $Button1.Add_Click({makeHashTable param1 param2})
    
    # 連想配列を渡すボタン
    $Button2 = 略
    $Button2.Add_Click({Calc})
    
[/code]

現在、設定したリストボックス内にある文字列をButton1のクリックで連想配列にするという内容で作成しています。  
一度の実行であればリンク先の方法で問題ありませんが、新たに文字列を追加或いは全て入れ直してButton1で連想配列を作成するとなると、keyが更新されるか重複すると思います。  
Button1のクリックで何度も新しいHashTableを作成できるようにしたい場合はどうするべきでしょうか。

私としてはやはり関数内で作成して渡すというやり方がわかりやすいです。  
しかし変数$HashTableは関数内で生成されるがそれは関数内のみ有効で外側からはみえないという話なので難しそうです...。  
良い方法ご存知でしたらよろしくお願いいたします。


CC BY-SA 4.0
2022-11-19T06:40:51.160
92309
2022-11-20T03:31:53.513
48769
question
powershell
PowerShellで新規HashTableを繰り返し作成したい


`$HashTable`を操作する前に [`Dictionary.Clear()`
メソッド](https://learn.microsoft.com/ja-
jp/dotnet/api/system.collections.generic.dictionary-2.clear?view=net-7.0)
を呼んで、空にすればいいのではないでしょうか。

* * *

前質問および本質問の意図は理解していますが、[PowerShellのスコープ設計](https://learn.microsoft.com/ja-
jp/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-7.3)を理解する必要があります。またそれだけでなく、PowerShellのスコープ設計とWinFormsのイベントコールバックを組み合わせるはかなりややこしいことになります。

  * [関数 `Function Name{}`](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_functions?view=powershell-7.3)や[スクリプトブロック`{}`](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_script_blocks?view=powershell-7.3)は変数スコープを持ちます。このため、`$Button1`のコールバックと`$Button2`のコールバックとで変数を共有することができません。
  * 変数スコープは呼び出し元のスコープを継承します。そのため、`$Button1`のコールバックと`$Button2`のコールバックの外側で定義した変数を **参照** することができます。  
先の回答はこのことを利用する提案でした。

  * 外側で定義した変数はあくまで参照できるだけであり、代入を行うとスコープ内の変数として **再定義** されます。このため、`$Button1`のコールバック内や`makeHashTable`関数内で代入を行っても外側で定義した変数を更新することはできず、`$Button2`のコールバックも参照できない、ということになります。
  * この制限を回避する方法は2種類あります。 
    * [スコープ修飾子](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-7.3#scope-modifiers)が用意されており`$global:HashTable`や`$script:HashTable`など適切なスコープを指定することで親スコープの変数にアクセスできます。もちろん更新も可能です。
    * [`Set-Variable`](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/set-variable?view=powershell-7.3)でスコープを指定して変数を更新できます。`Set-Variable -Name HashTable -Scope 1 -Value 設定したい値`ぐらいになるでしょうか。

繰り返しになりますが、これらを行うには正しいスコープの理解が必要で、例えばスクリプト化されていなければ`$script:HashTable`は使えなかったり、`makeHashTable`の中から更新する場合は2階層突き抜けるので`-Scope
2`と指定する必要があったりとかなり厄介です。

そのような努力をするよりは安易に`$Button1` `$Button2`と同じ階層で`$HashTable`を定義することをお勧めします。


CC BY-SA 4.0
2022-11-19T07:02:23.530
92310
2022-11-20T03:31:53.513
2022-11-20T03:31:53.513
4236
4236
92309
answer