首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PowerShell : GetNewClosure()和带验证的Cmdlets

PowerShell : GetNewClosure()和带验证的Cmdlets
EN

Stack Overflow用户
提问于 2013-11-05 03:45:35
回答 2查看 781关注 0票数 4

我正在尝试理解.GetNewClosure()在PowerShell 2的script cmdlet上下文中是如何工作的。

实际上,我有一个返回对象的函数,如下所示:

代码语言:javascript
复制
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*()装饰器--但这似乎很糟糕,而且相当晦涩。有没有办法融合这两种想法呢?

EN

回答 2

Stack Overflow用户

发布于 2014-07-16 02:58:25

"Attribute cannot be added“消息是(或者曾经是)一个PowerShell错误,我已经用this bug report把它提交给了微软。这个特定的问题似乎已经被修复了,(可能在V5.1左右。但是任何对Powershell闭包感兴趣的人都可能会发现下面的信息很有趣。

有一个在早期版本中有效的解决方法,但首先是一个简化的再现案例,它会产生相同的错误:

代码语言:javascript
复制
function Test-ClosureWithValidation {
    [CmdletBinding()]
    param(
        [Parameter()]
        [ValidateSet('Option1','Option2')]
        [String[]]$Options
    )
    [scriptblock] $closure = {"OK"}.GetNewClosure();
    $closure.Invoke()
}

Test-ClosureWithValidation -Options Option1

解决方法取决于这样一个事实: GetNewClosure()的工作方式是在调用脚本的上下文中迭代局部变量,将这些局部变量绑定到脚本的上下文中。该错误的发生是因为它复制了包含$Options属性的验证变量。您可以通过创建一个仅包含所需局部变量的新上下文来解决此错误。在上面的简单repro中,它是一个单行解决方法:

代码语言:javascript
复制
    [scriptblock] $closure = &{ {"OK"}.GetNewClosure();}

上面的代码行现在创建了一个不带局部变量的作用域。对于您的情况来说,这可能太简单了;如果您需要来自外部作用域的一些值,您可以只将它们复制到新作用域中的局部变量中,例如:

代码语言:javascript
复制
    [scriptblock] $closure = &{ 
        $options = $options; 
        {"OK $options"}.GetNewClosure();
    }

请注意,上面的第二行代码创建了一个新的$options变量,将外部变量的值赋给它,属性不会传播。

最后,在您的示例中,我根本不确定为什么需要调用GetNewClosure。变量$this不是一个普通的局部变量,无论您是否创建了闭包,它都将在您的脚本属性中可用。示例:

代码语言:javascript
复制
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
票数 5
EN

Stack Overflow用户

发布于 2013-11-05 08:29:13

我相信这可能行得通:

代码语言:javascript
复制
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 

.. }

这会将脚本块的创建延迟到运行时。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19775779

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档