我正在尝试理解.GetNewClosure()在PowerShell 2的script cmdlet上下文中是如何工作的。
实际上,我有一个返回对象的函数,如下所示:
function Get-AnObject {
param(
[CmdletBinding()]
[Parameter(....)]
[String[]]$Id
..
[ValidateSet('Option1','Option2')]
[String[]]$Options
)
...
$T = New-Object PSCustomObject -Property @{ ..... }
$T | Add-Member -MemberType ScriptProperty -Name ExpensiveScriptProperty -Value {
$this | Get-ExpensiveStuff
}.GetNewClosure()
..
}如果我没有验证集合选项,那么闭包看起来工作得很好。但是,如果包含它,新的闭包将失败,并显示以下错误。
使用"0“参数调用"GetNewClosure”时出现异常:“无法添加属性,因为这将导致具有值的变量选项无效。”
假设闭包正在尝试捕获对Cmdlet的调用的上下文。因为参数"Options“根本没有绑定,所以这与参数验证不是很好。
我认为可以通过将验证作为代码放在Cmdlet的主体中来避免这种情况,而不是使用Validate*()装饰器--但这似乎很糟糕,而且相当晦涩。有没有办法融合这两种想法呢?
发布于 2014-07-16 02:58:25
"Attribute cannot be added“消息是(或者曾经是)一个PowerShell错误,我已经用this bug report把它提交给了微软。这个特定的问题似乎已经被修复了,(可能在V5.1左右。但是任何对Powershell闭包感兴趣的人都可能会发现下面的信息很有趣。
有一个在早期版本中有效的解决方法,但首先是一个简化的再现案例,它会产生相同的错误:
function Test-ClosureWithValidation {
[CmdletBinding()]
param(
[Parameter()]
[ValidateSet('Option1','Option2')]
[String[]]$Options
)
[scriptblock] $closure = {"OK"}.GetNewClosure();
$closure.Invoke()
}
Test-ClosureWithValidation -Options Option1解决方法取决于这样一个事实: GetNewClosure()的工作方式是在调用脚本的上下文中迭代局部变量,将这些局部变量绑定到脚本的上下文中。该错误的发生是因为它复制了包含$Options属性的验证变量。您可以通过创建一个仅包含所需局部变量的新上下文来解决此错误。在上面的简单repro中,它是一个单行解决方法:
[scriptblock] $closure = &{ {"OK"}.GetNewClosure();}上面的代码行现在创建了一个不带局部变量的作用域。对于您的情况来说,这可能太简单了;如果您需要来自外部作用域的一些值,您可以只将它们复制到新作用域中的局部变量中,例如:
[scriptblock] $closure = &{
$options = $options;
{"OK $options"}.GetNewClosure();
}请注意,上面的第二行代码创建了一个新的$options变量,将外部变量的值赋给它,属性不会传播。
最后,在您的示例中,我根本不确定为什么需要调用GetNewClosure。变量$this不是一个普通的局部变量,无论您是否创建了闭包,它都将在您的脚本属性中可用。示例:
function Test-ScriptPropertyWithoutClosure {
[CmdletBinding()]
param(
[Parameter()]
[ValidateSet('Option1','Option2')]
[String[]]$Options
)
[pscustomobject]@{ Timestamp= Get-Date} |
Add-Member ScriptProperty ExpensiveScriptProperty {
$this | get-member -MemberType Properties| % Name
} -PassThru
}
Test-ScriptPropertyWithoutClosure -Options Option1 | fl发布于 2013-11-05 08:29:13
我相信这可能行得通:
function Get-AnObject {
param(
[CmdletBinding()]
[Parameter(....)]
[String[]]$Id
..
[ValidateSet('Option1','Option2')]
[String[]]$Options
)
...
$sb = [scriptblock]::create('$this | Get-ExpensiveStuff')
$T = New-Object PSCustomObject -Property @{ ..... }
$T | Add-Member -MemberType ScriptProperty -Name ExpensiveScriptProperty -Value $sb
.. }这会将脚本块的创建延迟到运行时。
https://stackoverflow.com/questions/19775779
复制相似问题