我注意到编写PowerShell类行有趣而奇怪的事情:
class A {
[object] WhereObject(){
return @(1,2) | Where-Object {$_ -gt 2}
}
[object] Where(){
return @(1,2).Where( {$_ -gt 2})
}
}
$a = new-object A
$a.WhereObject() # Throw exception Index was out of range. Must be non-negative and less than the size of the collection.
$a.Where() # Works well
看起来是设计使然。为什么这样工作?
解决方法
将“空”值显式转换为$ null的函数:
function Get-NullIfEmpty {
param(
[Parameter(ValueFromPipeline=$true)][array] $CollectionOrEmtpy
)
begin { $output = $null }
process
{
if($output -eq $null -and $CollectionOrEmtpy -ne $null){
$output = @()
}
foreach ($element in $CollectionOrEmtpy)
{
$output += $element
}
}
end { return $output }
}
在这种情况下,该方法将如下所示:
[object] WhereObject() {
return @(1,2) | Where-Object {$_ -gt 2} | Get-NullIfEmpty
}
我试图从类方法中返回一个空数组,但这也很棘手,因为对于常规函数来说,空数组也意味着“什么也没有”。如果您有像method1-> function-> method2-method1这样的调用链,则抛出相同的异常。因为该函数会将空数组转换为空。
因此,在我的情况下,转换为$ null最佳:)
答案 0 :(得分:4)
.Where()
运算符始终返回一个Collection<PSObject>
。但是,管道情况不返回任何内容。这是一个问题,因为调用脚本块的代码期望结果List
即result.Count == 1
中存在一个对象。流水线情况下没有对象,因此会出现索引超出范围错误。所以这是一个错误。我们仍然应该产生一个错误,但是应该是“非void方法必须返回一个值”或类似的错误。顺便说一句-code in question is here.
答案 1 :(得分:4)
(PowerShell v4 +) .Where()
方法 ,它在表达式模式, < em>始终返回[System.Collections.ObjectModel.Collection[psobject]]
的实例:
.Count
属性返回0
)。相反, Where-Object
cmdlet 使用管道语义,这意味着以下输出行为:>
如果没有输出 (如果没有任何内容与过滤器脚本块匹配),则返回值为“空集合”,从技术上讲是[System.Management.Automation.Internal.AutomationNull]::Value
单例。
如果单个 项匹配,则该项将按原样输出。
如果多个项匹配,并且它们收集在变量中/作为表达式的一部分进行评估,则它们将收集在[object[]]
数组中。
至于特定症状-自Bruce Payette's answer起已确认是 bug :
此错误自reported on GitHub起。
内部[List[object]]
实例用于收集通过内部管道执行的方法调用的输出。如果该内部管道输出“无”-即[System.Management.Automation.Internal.AutomationNull]::Value
- no 对象被添加到列表中。但是,后续代码假定列表中至少有一个对象,并且盲目访问索引0
,从而导致手头的错误。
更简单地再现问题:
class A {
# Try to return [System.Management.Automation.Internal.AutomationNull]::Value
# (which is what `& {}` produces).
[object] WhereObject(){ return & {} }
}
$a = new-object A
$a.WhereObject() # Throw exception Index was out of range. Must be non-negative and less than the size of the collection.
至于期望的行为:
如果该方法的代码返回“空集合” using C#'s default-value feature-参见this comment,似乎该修补程序将导致$null
获得输出。