当Where-Object返回一个项目时,PowerShell数组列表分配和Where-Object失败,适用于2个以上的项目

dkqlctbz  于 2023-02-04  发布在  Shell
关注(0)|答案(1)|浏览(110)

长期搜索者,第一次海报。:-)
将数组列表通过管道传输到Where-Object并将其分配回另一个数组列表时,如果Where-Object的结果是单个项目,则会生成转换错误。但如果返回两个或多个项目,则相同的命令会成功。这是PowerShell错误还是我遗漏了什么?
为什么会失败?

PS C:\> [System.Collections.ArrayList]$AL1 = @(1,2,3)
PS C:\> [System.Collections.ArrayList]$AL2 = $AL1 | Where-Object {$_ -ge 3}
Cannot convert the "3" value of type "System.Int32" to type "System.Collections.ArrayList".
At line:1 char:1
+ [System.Collections.ArrayList]$AL2 = $AL1 | Where-Object {$_ -ge 3}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

但是,如果Where-Object的结果是两个或多个项,则它不会失败。

PS C:\> [System.Collections.ArrayList]$AL1 = @(1,2,3)
PS C:\> [System.Collections.ArrayList]$AL2 = $AL1 | Where-Object {$_ -ge 2}
PS C:\> $AL2
2
3
PS C:\>

如果首先通过New-Object创建第二个数组列表,则赋值也会成功。

PS C:\> $AL3 = New-Object System.Collections.ArrayList
PS C:\> $AL3 = $AL1 | Where-Object {$_ -ge 3}
PS C:\> $AL3
3

在PS版本5.1.19041.1682和内核7.0.7上进行测试

jhdbpxl9

jhdbpxl91#

是的,这是预期的,PowerShell枚举所有输出,并且,因为表达式只产生一项:

$AL1 | Where-Object { $_ -ge 3 }

它试图将int强制为System.Collections.ArrayList类型,但是只有实现IEnumerable的类型才能强制为它,因此出现错误:

PS \> [System.Collections.ArrayList] 3

无效参数:无法将类型"System.Int32"的"3"值转换为类型"System. Collections. ArrayList"。
您有三种简单的解决方法:
1.不要将变量的类型限制为System.Collections.ArrayList,让PowerShell动态分配结果类型。
1.使用Array子表达式运算符@( ) Package 表达式,因此,无论表达式产生多少元素,类型始终为IEnumerable

[System.Collections.ArrayList] $AL1 = @(1, 2, 3)
[System.Collections.ArrayList] $AL2 = @($AL1 | Where-Object { $_ -ge 3 })

1.请改用.Where方法,该方法始终返回[Collection1](https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.collection-1?view=net-7.0)(一个IEnumerable`):

[System.Collections.ArrayList] $AL1 = @(1, 2, 3)
[System.Collections.ArrayList] $AL2 = $AL1.Where{ $_ -ge 3 }

使用Write-Output -NoEnumerate或逗号运算符,也可以实现其他解决方法:

[System.Collections.ArrayList] $AL1 = @(1, 2, 3)
[System.Collections.ArrayList] $AL2 = Write-Output ($AL1 | Where-Object { $_ -ge 3 }) -NoEnumerate
[System.Collections.ArrayList] $AL2 = , ($AL1 | Where-Object { $_ -ge 3 })

至于:
如果首先通过New-Object创建第二个数组列表,则赋值也会成功。
正确,在本例中您没有约束变量:

$AL3 = New-Object System.Collections.ArrayList
$AL3 = $AL1 | Where-Object { $_ -ge 3 }
$AL3.GetType() # => Int32, no longer an ArrayList

有关详细信息,请参阅相关文档:* * about Variables**.

相关问题