首页 > 解决方案 > ForEach 方法后 PowerShell 长度的奇怪行为

问题描述

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

> (1..3).ForEach({$_}).Length
1
1
1
> (1..3).ForEach({$_}).Count
3

标签: powershell

解决方案


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

例外情况是 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

实际上与以下内容相同:

(1..3).ForEach({ $_.Length })

以上解释了 ( 1, 1, 1) 输出。相比之下,[System.Collections.ObjectModel.Collection[psobject]]确实有一个原生类型 .Count属性,如预期的那样返回元素的计数。


背景资料:

笔记:

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

  • 相反,认为是集合的类型可能有也可能没有任何一个或两个这样的属性type-natively,并且在没有类型原生属性的情况下执行成员枚举

    • 具有原生类型属性的类型的显着示例是惰性枚举;例如,[Linq.Enumerable]::Range(1,3).Count产量1, 1, 1

哪些 .NET 类型 PowerShell 会考虑集合,因此会在管道中自动枚举:

  • 实现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属性实现)。


推荐阅读