ForEach 方法后 PowerShell 长度的奇怪行为

Eld*_*rry 2 powershell

官方文档中提到这Length是 的一个别名Count,但是我发现它们的行为不同的一种情况。此外,如果我ForEach用 替换 method ForEach-ObjectLength将会发出 3 。有人能解释一下吗?

> (1..3).ForEach({$_}).Length
1
1
1
Run Code Online (Sandbox Code Playgroud)
> (1..3).ForEach({$_}).Count
3
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 8

.Length.Count是彼此的别名,并且是PowerShell 添加到大多数对象中的所谓内在成员(属性) ,以便统一处理标量和集合(有关背景信息,请参阅此答案)。

例外情况是 PowerShell 将其视为集合的类型的对象,即它在管道中自动枚举的对象,其中包括[System.Collections.ObjectModel.Collection[psobject]]数组.ForEach()方法返回的类型的实例。

PowerShell 不会它所认为的集合的实例添加.Length和属性,因为它假定它们本身.Count具有此类属性(类型本机),并假定可以有效实现(而不是 PowerShell 必须执行枚举和对元素进行计数)。

这是一个合理的假设,通常适用于.Count,但很少适用于.Length(数组 ( ) 是存在并返回元素计数的System.Array一个值得注意的例子)。.Length

因此,通常使用.Count而不是更好.Length


当您访问.LengthPowerShell 视为集合的类型的实例时,但该类型没有此类类型本机属性,PowerShell 会执行成员访问枚举

  • 也就是说,它枚举集合并返回元素.Length属性值。

  • 在您的情况下,由于元素是标量(单个[int]对象),因此它们确实具有内在 .Length属性,在标量的情况下总是返回1

所以:

(1..3).ForEach({$_}).Length
Run Code Online (Sandbox Code Playgroud)

实际上等同于:

(1..3).ForEach({ $_.Length })
Run Code Online (Sandbox Code Playgroud)

上面解释了 ( 1, 1, 1) 输出。相比之下,[System.Collections.ObjectModel.Collection[psobject]]确实有一个类型本机 .Count属性,它按预期返回元素的计数。


背景资料:

笔记:

  • 只有那些 PowerShell 不考虑集合的类型才能获取内在函数.Count.Length属性。

  • 相反,被视为集合的类型可能具有或不具有任何此类属性type-natively,并且在缺少 type-native 属性的情况下将执行成员访问枚举。

    • 具有本机类型属性的类型的著名示例是惰性枚举;例如,[Linq.Enumerable]::Range(1,3).Count产量1, 1, 1

PowerShell 认为哪些 .NET 类型是集合(可枚举),因此会在管道中自动枚举:

  • 任何实现IEnumerable/IEnumerable`1 .NET 接口的类型

    • 但以下情况除外,不会自动枚举:

      • IDictionary/ IDictionary`2,特别包括[hashtable]( @{ ... },作为文字) 及其有序表亲OrderedDictionary( [ordered] @{ ... },作为文字)

      • XmlNode[xml], ( XmlDocument)的基本类型

      • 字符串( String); 请注意,'foo'.Countis 1(反映字符串被视为标量(单个事物)的内在属性),而'foo'.Lengthis 3(返回字符计数的类型本机属性)。

  • 另外System.Data.DataTable(它本身不实现IEnumerable,只有它的.Rows属性实现)。