Function PowerShell闭包中的捕获函数

Function PowerShell闭包中的捕获函数,function,powershell,closures,Function,Powershell,Closures,PowerShell闭包似乎没有捕获函数的定义: PS C:\> function x() { Write-Host 'original x' } PS C:\> function x-caller-generator() { return { Write-host 'Calling x!'; x }.GetNewClosure() } PS C:\> $y = x-caller-generator PS C:\> & $y Calling x! original

PowerShell闭包似乎没有捕获函数的定义:

PS C:\> function x() { Write-Host 'original x' }
PS C:\> function x-caller-generator() { return { Write-host 'Calling x!'; x }.GetNewClosure() }
PS C:\> $y = x-caller-generator
PS C:\> & $y
Calling x!
original x
PS C:\> function x() { Write-Host 'new x' }
PS C:\> & $y
Calling x!
new x
有什么方法可以获取函数的定义吗

我实际经历的是我创建了一个闭包,但是当我的闭包被执行时,函数不知何故超出了范围。(构建脚本模块正在做一些奇怪的事情。)类似这样的事情:

PS C:\> function closure-maker () {
>>     function x() { Write-Host 'x!' }
>>
>>     return { Write-host 'Calling x'; x }.GetNewClosure()
>> }
>>
PS C:\> $y = closure-maker
PS C:\> & $y
Calling x
The term 'x' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:3 char:39
+     return { Write-host 'Calling x'; x <<<<  }.GetNewClosure()
    + CategoryInfo          : ObjectNotFound: (x:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
PS C:\>函数闭包生成器(){
>>函数x(){Write Host'x!'}
>>
>>返回{Write host'Calling x';x}.GetNewClosure()
>> }
>>
PS C:\>$y=封口制造商
私人秘书长:\>&$y
呼叫x
术语“x”不能识别为cmdlet、函数、脚本文件或可操作程序的名称。请检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。
第3行字符:39

+return{Write host'Calling x';x嗯,我发现至少对简单函数有效。我们可以使用
Get Item
获取描述函数的对象,然后从中提取原始脚本。如下所示:

function x-caller-generator() {
    $xFunc = [ScriptBlock]::Create((Get-Item function:x).Definition)
    return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure()
}
如果从未重新定义函数(如我的示例中我的函数超出范围),我们可以避免取消定义,直接使用函数对象:

function closure-maker () {
    function x() { Write-Host 'x!' }

    $xFunc = Get-Item function:x
    return { Write-host 'Calling x'; & $xFunc }.GetNewClosure()
}
如果在执行闭包之前重新定义函数(至少在与原始函数相同的范围内),则第二种方法将不起作用。对象显然是动态的;它跟踪当前定义

我严重怀疑这是否适用于引用其他用户定义函数的函数,这些函数也可能超出范围,但我的用例并不要求这样做

样本输出:

创建脚本块

PS C:\> function x() { Write-Host 'original x' }
PS C:\> function x-caller-generator() { $xFunc = [ScriptBlock]::Create((Get-Item function:x).Definition); return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() }
PS C:\> $y = x-caller-generator
PS C:\> & $y
Calling x!
original x
PS C:\> function x() { Write-Host 'new x' }
PS C:\> & $y
Calling x!
original x
使用函数对象

PS C:\> function closure-maker () {
>>     function x() { Write-Host 'x!' }
>>
>>     $xFunc = Get-Item function:x
>>     return { Write-host 'Calling x'; & $xFunc }.GetNewClosure()
>> }
>>
PS C:\> $y = closure-maker
PS C:\> & $y
Calling x
x!
尝试将对象与第一个示例一起使用无效

PS C:\> function x() { Write-Host 'original x' }
PS C:\> function x-caller-generator() { $xFunc = Get-Item function:x; return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() }
PS C:\> $y = x-caller-generator
PS C:\> & $y
Calling x!
original x
PS C:\> function x() { Write-Host 'new x' }
PS C:\> & $y
Calling x!
new x

一个小的修正将使第一个示例起作用:

clear
function x() { Write-Host 'original x' }
function x-caller-generator() { 
      $xFunc = $function:x; # instead of Get-Item
      return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() 
}
$y = x-caller-generator
& $y
function x() { Write-Host 'new x' }
& $y
输出:

Calling x!
original x
Calling x!
original x
PowerShell有太多外观相似但实际行为不同的功能。您可以使用$function prefix获取函数对象。有人可能认为它与get项的工作方式相同,但它不