How to use .GetNewClosure() with the -Action value for an EngineEvent
& {
$action = & { $y = 100
return { write-host "Value: $y" }.getnewclosure()
}
[void] (register-engineevent -sourcei "foo" -action $action)
[void] (new-event -sourcei "foo")
}
The code above prints Value:
, while I开发者_JAVA技巧'd expect it to print Value: 100
. Is something missing here?
The engine is calling GetNewClosure()
on it, which is a better thing for it to do than not.
When I ran the above, I got an output of only Value:
, but then I globally declared $y = 25
and ran [void](new-event -sourcei 'foo')
again, the output was Value: 25
. Then I changed its value again, $y = 38
, and ran the event again: Value: 38
.
If what you want is to bake in the value of $y
at the time you create the action, one way to do that is to create the scriptblock in such a way that the value of $y
becomes a literal or part of a literal:
$action = &{ $y = 100
return (invoke-expression "{write-host 'Value: $y'}")
}
This first parses the string to insert the value, so Invoke-Expression
ends up doing the equivalent of this:
{write-host 'Value: 100'}
I'm not sure if there are any other ways to bake in the value other than composing the entire content of the scriptblock in a string and passing it through Invoke-Expression
.
In response to your comment, further explanation of closures:
> $action100 = &{$y = 100; return {write-host "Value: $y"}.GetNewClosure()}
> &$action100
Value: 100
That's the result you expect, and that's what you get, because the scriptblock is still "closed" around the value of $y
in the scope where GetNewClosure()
was called.
> $y = 25
> &$action100
Value: 100
Still closed around the $y
that is 100
.
> $action25 = $action100.GetNewClosure()
> &$action25
Value: 25
This produces a new scriptblock that encloses variables in the current scope. It makes it re-evaluate what $y
is in that scriptblock, and in this context, $y
is now 25.
> $y = 38
> &$action100
Value: 100
> &$action25
Value: 25
> &($action100.GetNewClosure())
Value: 38
At this point, because $y
is declared globally now, when you call New-Event
it will use GetNewClosure()
and re-evaluate $y
to 38
, and print Value: 38
. You've been getting Value:
because in the context where the engine events call GetNewClosure()
the variable $y
is not defined, so "Value: $y"
becomes "Value: "
.
精彩评论