2013-02-09 3 views
1

Я начинающий Powershell, хотя и не программирование n00b. Я пытаюсь создать IDisposable/RAII стиль безотказного шаблон, вроде как в:Powershell параметр namespace collision

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 на пути и поп-местоположение на выходе. Поэтому у меня есть:

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

Я считаю, что $ выполнить параметры в Push-Location-FailSafe сталкивается с $ выполнения параметров в FailSafe функции.

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 

Причина, я думаю, что это имя столкновения, что если переименовать $ выполнить до $ execute2 в Push-Location-FailSafe, он отлично работает:

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] 

Что плохого в моем понимании параметры?

ответ

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, когда создает скриптовый блок.

проще и лучше способ, чтобы решить просто использовать различные variablenames так что нет никакого столкновения в первую очередь :-)

Смежные вопросы