不久前我改变了我的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 错误/怪癖?
最佳答案
您原来的方法确实在概念上存在缺陷,因为您多次输出同一对象,迭代地修改其属性。
输出差异由管道的逐项处理解释:
输出到控制台(通过
ft
/Format-Table
)打印当时> 每次迭代中$PSObject
的状态,看起来一切都很好。
相比之下,在变量中进行捕获反射(reflect)了所有迭代完成后
$PSObject
的状态,此时它仅包含最后迭代的值,Name3
和3
。
您可以验证输出数组 $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
}
}
关于powershell - 为管道重用自定义对象时出现意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49192685/