Length
属性在我测试的所有数组中都能正常工作,除了一个奇怪的情况:
PS> @(@()).Length
0
并不是说空数组通常会被省略:
PS> @(@(), @()).Length
2
PS> @(@(), @(), @()).Length
3
怎么回事?
-
@(...)
,数组子表达式操作符不是数组构造函数,它是数组"保证符">(参见下一节),并且嵌套@(...)
操作是没有意义的.@(@())
实际上与@()
相同,即[object[]]
类型的空数组。
-
要无条件构造数组,请使用
,
,数组构造函数操作符。-
要为单个对象构造数组包装器,请使用
,
的一元形式,正如Abraham Zinala所建议的:# Create a single-element array whose only element is an empty array. # Note: The outer enclosure in (...) is only needed in order to # access the array's .Count property. (, @()).Count # -> 1
-
请注意,我使用了.Count
而不是上面的.Length
,这更符合powershell的习惯用法;.Count
适用于不同的集合类型。尽管System.Array
不直接实现.Count
,但它通过ICollection
接口实现,并且PowerShell允许访问接口成员而不需要强制转换。
背景信息:
-
@(...)
的主要目的是确保从基于管道的命令(例如,@(Get-ChildItem *.txt)
)收集的输出对象总是作为数组收集。(总是[object[]]
类型)-即使...
只产生一个输出对象。-
如果需要获取数组,则必须使用
@(...)
,因为收集碰巧只包含一个对象的输出将默认按原样收集,即不是包装在数组中(这也适用于使用$(...)
,子表达式操作符);只有对于多个输出对象才使用数组,该数组始终是[object[]]
类型的。 -
注意PowerShell命令(通常)不输出集合;相反,它们将一个接一个的(通常是开放式的)对象流到管道中;因此,捕获命令输出需要收集流对象—更多信息请参见此回答。
-
-
@(...)
的次要目的是方便定义数组字量,例如@('foo', 'bar')
-
注意:
-
使用
@(...)
来实现这个目的在最初的设计中不是,但是这种使用变得如此普遍,以至于在PowerShell的第5版中实现了一个优化,例如,1, 2
——它足以声明一个2元素数组——也可以表示为@(1, 2)
,而没有不必要的处理开销。 -
有利的一面是,
@(...)
总体上在视觉上很独特,在语法上也很方便,特别是用于声明空(@()
)或单元素数组(例如@(42)
)—如果没有@(...)
,它们将不得不分别表示为[object[]]:new()
和, 42
。 -
然而,
@(...)
的这种用法会引起误解,认为它是一个无条件的数组构造函数,但事实并非如此;简而言之:在@(...)
操作周围包装额外的@(...)
操作不会创建嵌套数组,它是一个昂贵的无操作;例如:@(42) # Single-element array @(@(42)) # !! SAME - the outer @(...) has no effect.
-
-
当
@(...)
应用于(非数组文字)表达式时,该表达式的计算结果是发送到管道的,该使PowerShell枚举它。[1]也就是说,如果表达式结果是一个集合,它的元素被一个接一个地发送到管道,类似于命令的流输出,然后再被收集到[object[]]
数组中.# @(...) causes the [int[]]-typed array to be *enumerated*, # and its elements are then *collected again*, in an [object[]] array. $intArray = [int[]] (1, 2) @($intArray).GetType().FullName # -> !! 'System.Object[]'
防止此枚举和重新收集:
按原样使用表达式,必要时将其括在
中(...)
要再次确保返回数组,
@(...)
的有效替代方法是使用[array]
强制转换;唯一需要注意的是,如果表达式求值为$null
,那么结果也将是$null
($null -eq [array] $null
):# With an array as input, an [array] cast preserves it as-is. $intArray = [int[]] (1, 2) ([array] $intArray).GetType().FullName # -> 'System.Int32[]' # With a scalar as input, a single-element [object[]] array is created. ([array] 42).GetType().FullName # -> 'System.Object[]'
-
[1]请参阅本回答的底部部分,了解PowerShell认为管道中可枚举的。net类型。