如何使用.GetNewClosure()和EngineEvent的-Action值

时间:2011-08-01 22:36:47

标签: powershell closures

& { 
    $action = & { $y = 100
        return { write-host "Value: $y" }.getnewclosure()
    }

    [void] (register-engineevent -sourcei "foo" -action $action)
    [void] (new-event -sourcei "foo")
}

上面的代码打印Value:,而我希望它打印Value: 100。这里缺少什么?

1 个答案:

答案 0 :(得分:3)

引擎正在调用GetNewClosure(),这对它来说是一件好事。

当我运行上面的内容时,我得到的输出只有Value:,但我全局声明$y = 25并再次运行[void](new-event -sourcei 'foo'),输出为Value: 25。然后我再次更改其值$y = 38,然后再次运行该事件:Value: 38

如果你想要的是在创建动作时烘焙$y的值,那么一种方法是以$y的值创建脚本块成为文字或文字的一部分:

$action = &{ $y = 100
    return (invoke-expression "{write-host 'Value: $y'}")
}

首先解析字符串以插入值,因此Invoke-Expression最终会执行相应的操作:

{write-host 'Value: 100'}

我不确定除了在字符串中编写scriptblock的整个内容并将其传递给Invoke-Expression之外,是否还有其他方法可以烘焙该值。


在回复您的评论时,对闭包的进一步解释:

> $action100 = &{$y = 100; return {write-host "Value: $y"}.GetNewClosure()}
> &$action100
Value: 100

这是您期望的结果,这就是您所获得的结果,因为在调用$y的范围内,脚本块仍然围绕GetNewClosure()的值“关闭”。

> $y = 25
> &$action100
Value: 100

$y 100附近仍然关闭。

> $action25 = $action100.GetNewClosure()
> &$action25
Value: 25

这将生成一个新的scriptblock,它包含当前作用域中的变量。它会重新评估该脚本块中$y的内容,在此上下文中,$y现在为25。

> $y = 38
> &$action100
Value: 100

> &$action25
Value: 25

> &($action100.GetNewClosure())
Value: 38

此时,由于现在全局声明$y,当您致电New-Event时,它会使用GetNewClosure()并重新评估$y38,并打印Value: 38。您已获得Value:,因为在引擎事件调用GetNewClosure()的上下文中,未定义变量$y,因此"Value: $y"变为"Value: "