【问题标题】:Unexpected results when reusing a custom object for the pipeline为管道重用自定义对象时出现意外结果
【发布时间】:2018-08-17 23:05:01
【问题描述】:

不久前,我更改了我的 Join-Object cmdlet,这似乎导致了一个在我的任何测试中都没有发现的错误。
更改的目的主要是最小化代码并尝试通过准备自定义 PSObject 并在管道中重用它来提高性能。
由于Join-Object cmdlet 相当复杂,我创建了一个简化的cmdlet 来显示具体问题:
(PowerShell 版本为:5.1.16299.248

Function Test($Count) {
    $PSObject = New-Object PSObject -Property @{Name = $Null; Value = $Null}
    For ($i = 1; $i -le $Count; $i++) {
        $PSObject.Name = "Name$i"; $PSObject.Value = $i
        $PSObject
    }
}

直接测试输出完全符合我的预期:

Test 3 | ft

Value Name
----- ----
    1 Name1
    2 Name2
    3 Name3

假设我是否将结果分配给变量(例如$a)并不重要,但确实如此:

$a = Test 3
$a | ft

Value Name
----- ----
    3 Name3
    3 Name3
    3 Name3

所以,除了分享这个经验,我想知道这是编程缺陷还是 PowerShell 错误/怪癖?

【问题讨论】:

    标签: powershell pipeline psobject new-object


    【解决方案1】:

    您的原始方法在概念上确实存在缺陷,因为您要多次输出相同对象,并反复修改其属性

    输出差异由管道的逐项处理解释

    • 输出到控制台(通过ft/Format-Table)在每次迭代中打印$PSObjectthen-current状态,这给出一切都很好的样子。

    • 在变量中捕获,相比之下,反映$PSObject的状态在所有迭代完成后,此时它只包含last 迭代的值,Name33


    您可以验证输出数组$a 确实引用了相同的自定义对象三次,如下所示:

    [object]::ReferenceEquals($a[0], $a[1]) # $True
    [object]::ReferenceEquals($a[1], $a[2]) # $True
    

    因此,解决方案是每次迭代中创建一个独特的[pscustomobject] 实例:

    PSv3+ 提供了用于创建自定义对象的语法糖:您可以将哈希表(文字)转换为 [pscustomobject]。由于这也每次都会创建一个新实例,因此您可以使用它来简化您的功能:

    Function Test($Count) {
      For ($i = 1; $i -le $Count; $i++) {
        [pscustomobject] @{ Name = "Name$i"; Value = $i  }
      }
    }
    

    这是您自己的PSv2 兼容解决方案

    Function Test($Count) {
        $Properties = @{}
        For ($i = 1; $i -le $Count; $i++) {
            $Properties.Name = "Name$i"; $Properties.Value = $i
            New-Object PSObject -Property $Properties
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-09-03
      • 2014-01-21
      • 2014-09-27
      • 2016-01-04
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多