将自定义对象重新用于管道时出现意外结果 [英] Unexpected results when reusing a custom object for the pipeline

查看:90
本文介绍了将自定义对象重新用于管道时出现意外结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前一段时间,我更改了我的 Join-Object cmdlet,该cmdlet似乎引起了一个在任何情况下都没有发现的错误.我的测试.
更改的目的主要是通过准备自定义PSObject并在管道中重用此代码来最大程度地减少代码并尝试提高性能.
由于 Join-Object cmdlet非常复杂,因此我创建了一个简化的cmdlet来显示特定问题:
(PowerShell版本为:5.1.16299.248)

A while ago I changed my Join-Object cmdlet which appeared to cause a bug which didn’t reveal in any of my testing.
The objective of the change was mainly code minimizing and trying to improve performance by preparing a custom PSObject and reusing this in the pipeline.
As the Join-Object cmdlet is rather complex, I have created a simplified cmdlet to show the specific issue:
(The PowerShell version is: 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
    }
}

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

Directly testing the output gives exactly what I expected:

Test 3 | ft

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

假设我是否将结果分配给变量(例如$a)都没有关系,但是确实如此:

Presuming that it shouldn't matter whether I assign the result to a variable (e.g. $a) or not, but it does:

$a = Test 3
$a | ft

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

因此,除了分享这种经验之外,我想知道这是编程缺陷还是PowerShell错误/怪癖?

So, apart from sharing this experience, I wonder whether this is programming flaw or a PowerShell bug/quirk?

推荐答案

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

Your original approach is indeed conceptually flawed in that you're outputting the same object multiple times, iteratively modifying its properties.

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

  • 输出到控制台(通过ft/Format-Table)会在每次迭代中打印 then-then-current 状态,从而得出看起来一切都很好.

  • Outputting to the console (via ft / Format-Table) prints the then-current state of $PSObject in each iteration, which gives the appearance that everything is fine.

捕获到变量反映了在所有迭代完成后的状态 ,此时它仅包含 last 迭代的值Name33.

Capturing in a variable, by contrast, reflects $PSObject's state after all iterations have completed, at which point it contains only the last iteration's values, Name3 and 3.

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

You can verify that output array $a indeed references the very same custom object three times as follows:

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


因此,解决方案是在每次迭代创建一个不同的[pscustomobject]实例:


The solution is therefore to create a distinct [pscustomobject] instance in each iteration:

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

PSv3+ offers syntactic sugar for creating custom objects: you can cast a hashtable (literal) to [pscustomobject]. Since this also creates a new instance every time, you can use it to simplify your function:

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
    }
}

这篇关于将自定义对象重新用于管道时出现意外结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆