为管道重用自定义对象时出现意外结果
Unexpected results when reusing a custom object for the pipeline
不久前,我更改了我的 Join-Object
cmdlet,它似乎导致了一个错误,但在我的任何测试中都没有发现。
objective 更改主要是代码最小化并尝试通过准备自定义 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 bug/quirk?
你原来的方法确实在概念上有缺陷,因为你多次输出同一个对象,迭代地修改它的属性。
输出中的差异由管道的item-by-item处理解释:
输出到控制台(通过ft
/Format-Table
)打印then-current 每次迭代中的 $PSObject
状态,看起来一切正常。
在变量中捕获,相比之下,反映$PSObject
的状态在所有迭代后已完成,此时它仅包含 last 迭代的值,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
}
}
不久前,我更改了我的 Join-Object
cmdlet,它似乎导致了一个错误,但在我的任何测试中都没有发现。
objective 更改主要是代码最小化并尝试通过准备自定义 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 bug/quirk?
你原来的方法确实在概念上有缺陷,因为你多次输出同一个对象,迭代地修改它的属性。
输出中的差异由管道的item-by-item处理解释:
输出到控制台(通过
ft
/Format-Table
)打印then-current 每次迭代中的$PSObject
状态,看起来一切正常。在变量中捕获,相比之下,反映
$PSObject
的状态在所有迭代后已完成,此时它仅包含 last 迭代的值,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
}
}