powershell 为什么GetType()返回Object[]作为数组的类型,但一个错误的方法调用错误说它是数组中第0个元素的类型?

cunj1qz1  于 2023-06-06  发布在  Shell
关注(0)|答案(1)|浏览(569)

所以,我创建一个数组,调用GetType(),然后我(合理地)得到答案Object[]。然而,如果我给予它一个坏的方法,我会得到错误消息中第0个元素的类型。
只是想更多地理解Powershell--我假设这是因为Powershell在数组上找不到方法的情况下打开数组,然后在第0个数组上也失败,从而抛出完整的错误?

PS C:\Users\x> $i = @(1)
PS C:\Users\x> $i.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS C:\Users\x> $i.HerpDerp()
InvalidOperation: Method invocation failed because [System.Int32] does not contain a method named 'HerpDerp'.
PS C:\Users\x> $a = @("hi")
PS C:\Users\x> $a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS C:\Users\x> $a.HerpDerp()
InvalidOperation: Method invocation failed because [System.String] does not contain a method named 'HerpDerp'.
PS C:\Users\x> $m = @("hi",1)
PS C:\Users\x> $m.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS C:\Users\x> $m.HerpDerp()
InvalidOperation: Method invocation failed because [System.String] does not contain a method named 'HerpDerp'.
plicqrtu

plicqrtu1#

相关信息在评论中,但我认为你的问题值得一个回答帖子:
您看到的是**member-access enumeration的效果,这是一个方便的PowerShell功能,其中访问 * 数组 (类似列表的集合)上的成员(属性或方法)隐式访问 * 其元素上的成员,一个接一个**,将结果作为数组返回,* 除非 * 只有 * 一个 * 结果,该结果按原样返回;[1]例如:

# Even though .Year is applied to the *array*, PowerShell returns 
# the .Year property values from the two [datetime] instances that
# are the *elements* of that array; e.g., in 2023: 
#   @( 2023, 2022 )
@( (Get-Date), (Get-Date).AddYears(-1) ).Year

只在指定的成员不存在 * 在数组本身*时有效,因为数组本身的成员优先;例如:

# Returns 3, the *array's* .Length property value (count of elements), 
# not the length of the strings stored in the array's elements.
@( 'foo', 'bar', 'baz' ).Length

这也解释了为什么$i.GetType()返回 * 数组的 * 类型。
当应用成员访问枚举 * 时,(默认)行为会因您访问的是 * 属性 * 还是 * 方法*而有所不同:

    • 属性 * 访问:
  • 任何 * 不具有 * 指定属性的数组元素 * 都不会对输出做出贡献 *;如果 no 数组元素具有这样的属性,则总体结果为$null
# Outputs only 2023 (for instance), because [int] 42 has no .Year property.
@( (Get-Date), 42 ).Year
  • 注意:如果属性 exists 但是 * 恰好包含$null *,则它 is 包含在结果中。

但是,由于至少在PowerShell 7.3.4中存在 bug,如果属性 * doesn 't * exist,则[pscustomobject]示例也会贡献$null-请参见GitHub issue #13752

    • 方法 * 访问:
  • 如果任何数组元素 * 没有 * 指定名称的方法-或者如果方法调用导致 * 异常 * -则会发生 * 语句终止错误 *,这意味着 * 没有 * 成功输出,并且只报告 * 一个 * 错误,即第一个没有方法/导致异常的元素(这解释了.HerpDerp()调用的结果):
# !! Statement fails as a whole, because [int] (System.Int32)
# !! doesn't have a .ToShortDateString() method.
@( (Get-Date), 42 ).ToShortDateString()
  • 请注意,虽然您可以使用try / catch语句处理/沉默这样的错误,但您仍然不会从那些具有该方法(并且没有导致异常)的数组元素中获得部分结果。

请注意,上面的内容意味着触发语句终止错误的不一定是 first 元素,如果不是,则对早期元素的调用结果实际上是 * discovered *。
这有点问题,因为方法调用可能会产生副作用(并且可能没有输出),在这种情况下,您可能需要确定在哪些元素上成功执行了方法调用。
[1]在这样做时,成员访问枚举模仿了PowerShell管道的行为,这可能令人惊讶。参见GitHub issue #6802进行讨论。

相关问题