Есть ли способ выборочного захвата переменных в контексте блока скрипта внутри модулей?
Предположим, вы определили две функции в модуле (т.е. .psm1
файл):
function f1{
param($x1)
$a1 = 10
f2 $x1
}
function f2{
param($x2)
$a2 = 100
& $x2
}
Теперь предположим, что вы запускаете следующее:
PS C:\> $a0 = 1
PS C:\> $x0 = {$a0+$a1+$a2}
PS C:\> f1 $x0
1
$x2
сохраняет контекст командной строки, несмотря на то, что вызывается внутри $f2
, Это держит, если вы измените &
в .
,
Замена $xn
с $xn.GetNewClosure()
в модуле затем вызывая f1
захватывает значение 100
но нет 10
:
PS C:\> f1 $x0
101
PS C:\> f1 $x0.GetNewClosure
101
Это происходит потому, что звонит .GetNewClosure()
внутри f2
"перезаписывает" значение $a1
захвачен в f1
,
Есть ли способ выборочного захвата переменных в скрипт-блоках? Работая на примере, есть ли способ захватить оба $a1
внутри f1
а также $a2
внутри f2
?
1 ответ
Я надеялся, что есть встроенный способ достижения этого. Самая близкая вещь, которую я нашел, была [scriptblock]::InvokeWithContext()
, Обработка параметров для InvokeWithContext()
вручную становится довольно грязно Мне удалось инкапсулировать беспорядок, определив пару вспомогательных функций в другом модуле:
function ConvertTo-xScriptblockWithContext{
param([parameter(ValueFromPipeline=$true)]$InputObject)
process{
$InputObject | Add-Member -NotePropertyMembers @{variablesToDefine=@()}
{$InputObject.InvokeWithContext(@{},$InputObject.variablesToDefine)}.GetNewClosure() |
Add-Member -NotePropertyMembers @{ScriptBlockWithContext=$InputObject} -PassThru
}}
function Add-xVariableToContext{
param(
[parameter(ValueFromPipeline=$true)]$InputObject,
[parameter(position=1)]$Name,
[parameter(position=2)]$Value
)
process{
$exists = $InputObject.ScriptBlockWithContext.variablesToDefine | ? { $_.Name -eq $Name }
if ($exists) { $exists = $Value }
else{ $InputObject.ScriptBlockWithContext.variablesToDefine += New-Object 'PSVariable' @($Name,$Value) }
}}
Затем, f1
а также f2
добавьте переменные в контекст блока скрипта, используя Add-xVariableToContext, когда он проходит:
function f1{
param($x1)
$a1 = 10
$x1 | Add-xVariableToContext 'a1' $a1
f2 $x1
}
function f2{
param($x2)
$a2 = 100
$x2 | Add-xVariableToContext 'a2' $a2
& $x2
}
Заметить, что $x2
вызывается, как и любой другой скрипт-блок, поэтому его можно безопасно использовать с переменными, добавленными в его контекст, всем, что принимает скрипт-блоки. Создание новых скриптовых блоков, добавление $a0
в их контексте, и передавая их f1
выглядит так:
$a0 = 1
$x0a,$x0b = {$a0+$a1+$a2},{$a0*$a1*$a2} | ConvertTo-xScriptblockWithContext
$x0a,$x0b | Add-xVariableToContext 'a0' $a0
f1 $x0a
f1 $x0b
#111
#1000