【问题标题】:Is there a way to selectively capture variables in a scriptblock's context inside modules?有没有办法在模块内的脚本块上下文中选择性地捕获变量?
【发布时间】:2015-05-03 08:18:19
【问题描述】:

假设您在一个模块中定义了两个函数(即.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

发生这种情况是因为在f2 中调用.GetNewClosure() 会“覆盖”在f1 中捕获的$a1 的值。

有没有办法选择性地捕获脚本块中的变量?从这个例子开始,有没有办法在f1 中捕获$a1f2 中的$a2

【问题讨论】:

  • 我相信您正在寻找的概念是“范围”。 link
  • 使用$global:a1 = 10创建变量时可以在全局范围内创建变量你已经发现“当你使用调用运算符(&)运行一个函数或脚本时,它不是添加到当前作用域”和“要将函数添加到当前作用域,请在函数调用中的函数路径和名称之前键入一个点 (.) 和一个空格。”您还可以在创建变量后使用 Set-Variable 设置范围,或者在创建时使用 New-Variable 设置范围。 Another post about Scopes
  • @BoogaRoo Scope 已在此问题的标签中。我不了解使用.Set-Variable 如何帮助有选择地捕获脚本块上下文中的变量。你有一个例子来说明你的意思吗?

标签: variables powershell scope closures scriptblock


【解决方案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) }
}}

然后,f1f2 在脚本块通过时使用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 2020-05-01
    • 2014-09-26
    • 1970-01-01
    相关资源
    最近更新 更多