1

私はPowershellの初心者ですが、プログラミングn00bではありません。次のようなIDisposable/RAIIスタイルのフェイルセーフパターンを作成しようとしています。

http://www.sbrickey.com/Tech/Blog/Post/IDisposable_in_PowerShell

ので、私は持っています:

Function global:FailSafeGuard
{
param (
[parameter(Mandatory=$true)] [ScriptBlock] $execute,
[parameter(Mandatory=$true)] [ScriptBlock] $cleanup
)

    Try { &$execute }
    Finally { &$cleanup }
}

私はそれを使用して、別のディレクトリで一連のタスクを実行しようとしています。途中でPush-Locationを使用し、途中でPop-Locationを使用します。ので、私は持っています:

Function global:Push-Location-FailSafe
{
param (
$location,
[ScriptBlock] $execute
)
    FailSafeGuard {
        Push-Location $location;
        &$execute
        } { Pop-Location }  
}

Push-Location-FailSafeの$executeパラメーターがFailSafe関数の$executeパラメーターと衝突していることがわかりました。

Push-Location-FailSafe "C:\" {dir}
The expression after '&' in a pipeline element produced an invalid object. It must result in a command name, script block or CommandInfo object.
At C:\TEMP\b807445c-1738-49ff-8109-18db972ab9e4.ps1:line:20 char:10
+         &$ <<<< execute

名前の衝突だと思う理由は、Push-Location-FailSafeで$executeの名前を$execute2に変更すると、正常に機能するためです。

Push-Location-FailSafe "C:\" {dir}
    Directory: C:\

Mode                LastWriteTime     Length Name   
----                -------------     ------ ----   
d----        2011-08-18     21:34            cygwin 
d----        2011-08-17     01:46            Dell   
[snip]

パラメータの理解の何が問題になっていますか?

4

1 に答える 1

1

問題は、スクリプトブロックとそれらが変数を処理する方法にあります。スクリプトブロック内の変数は、実行されるまで展開されません。このため、あなたはループにぶつかっています。披露させて:

メソッドを呼び出すとPush-Location-Failsafe、変数は次のようになります。

[DBG]: PS C:\>> (Get-Variable execute).Value
 dir 

しかし、次に内部関数を呼び出すとFailSafeGuard$execute変数は次のように変更されます。

[DBG]: PS C:\>> (Get-Variable execute).Value

        Push-Location $location;
        & $execute

これで、try { }ブロックの実行が開始されると、変数の展開が開始されます。展開$executeすると、次のようになります。

Try { 
    Push-Location $location;
    & $execute 
}

その後、再び拡大$executeします。tryブロックは次のようになります。

Try { 
    Push-Location $location;
    & {
        Push-Location $location;
        & $execute
      } 
}

そして、再帰によって引き起こされる無限ループに陥りました。これを修正するには$execute、文字列内で変数を展開し、そこからスクリプトブロックを作成します。このような:

Function global:Push-Location-FailSafe
{
param (
$location,
[ScriptBlock] $execute
)
    FailSafeGuard ([ScriptBlock]::Create("
        Push-Location $location;
        & $execute")) { Pop-Location }  
}

$execute内部に変数を含めると、この特定のソリューションで問題が発生することに注意してください。例:$execute = { $h = dir }スクリプトブロックを作成するときに$hを展開しようとするため。

それを解決するためのより簡単でより良い方法は、そもそも衝突がないように異なる変数名を使用することです:-)

于 2013-02-09T21:20:34.730 に答える