Powershell 显示 JSON-object 和 ADDRESS-属性 的错误输出
Powershell showing wrong output for JSON-object and ADDRESS-property
我目前正在努力将 JSON 字符串转换为对象数组,并通常处理每个对象的 properties/attributes。
这是一个简单的演示,展示了例如属性"address"好像有点特殊:
cls
$json = '[{"id":"1","address":"1"},{"id":"2","address":"2"}]'
$list = $json | ConvertFrom-Json
$list.id # OK
$list.address # gives a weired result - is this a bug?
$list.GetEnumerator().address # that works
这是输出:
1
2
OverloadDefinitions
-------------------
System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Address(int )
1
2
如您所见,我需要添加“.GetEnumerator()”以获得正确的 "address" 值。
这是预期的吗?为了安全起见,我应该始终使用“.GetEnumerator()”吗?
因为 $list
是一个 array (集合),使用 $list.id
执行 member-access enumeration;也就是说,.id
属性 在每个元素 上自动访问 ,结果值作为数组返回 ([object[]]
)[1].
但是,如果数组/集合类型本身 有一个该名称的成员(属性 或方法),它 优先 ,这就是你的情况:.NET 数组有一个 .Address
方法(由运行时添加 - 参见 this answer),这就是抢占访问 元素的 .Address
属性.
(您看到的是 PowerShell 对方法签名(重载)的表示,这是您仅通过名称访问方法时得到的结果,而不是通过附加 ((...)
) 实际调用它);试试 'foo'.ToUpper
,例如。)
PowerShell 没有提供明确的运算符语法来区分直接成员访问和成员访问枚举是 [GitHub 问题 #7445](https://github.com/PowerShell/PowerShell/issues/7445) 的主题,但现有行为不太可能改变。
解决该问题的最有效方法是使用 PSv4+ .ForEach()
数组方法,该方法始终针对集合的 元素:
$list = '[{"id":"1","address":"1"},{"id":"2","address":"2"}]' | ConvertFrom-Json
$list.ForEach('address')
警告:如果您是 运行 Windows PowerShell 和 $list
在某些情况下只能导致 单个 pscustomobject
而不是 数组 ,您必须 将数组子表达式运算符@(...)
中的$list
括起来,以确保.ForEach()
方法可用。这是一个 [pscustomobject]
-specific bug(假设即使是单个对象也应该始终有一个 .ForEach()
方法),它已在 PowerShell (Core) 6+.中修复。
# @(...) is necessary in Windows PowerShell only.
@($list).ForEach('address')
注:
从技术上讲,这个 returns 是一个 [System.Collections.ObjectModel.Collection[PSObject]]
集合,但在大多数情况下,您可以像使用常规 [object[]]
PowerShell 数组一样使用它。
与成员访问枚举不同,如果输入集合中只有 一个 元素,也会返回一个集合实例(而不是返回该元素的 属性 值原样,成员访问枚举的方式)。
在 PSv3- 中,您可以使用 ForEach-Object
cmdlet,或 Select-Object -ExpandProperty
:
$list | ForEach-Object address # PSv2: | ForEach-Object { $_.address }
# OR
$list | Select-Object -ExpandProperty address
[1] 如果集合中只有 one 元素,则其 属性 值按原样返回,不包含在 (单元素)数组,这与在变量中收集 pipeline 输出时应用的逻辑相同。 GitHub issue #6802.[=37= 中讨论了这种逻辑在 表达式 上下文的成员访问枚举的上下文中可能是意外的]
我目前正在努力将 JSON 字符串转换为对象数组,并通常处理每个对象的 properties/attributes。
这是一个简单的演示,展示了例如属性"address"好像有点特殊:
cls
$json = '[{"id":"1","address":"1"},{"id":"2","address":"2"}]'
$list = $json | ConvertFrom-Json
$list.id # OK
$list.address # gives a weired result - is this a bug?
$list.GetEnumerator().address # that works
这是输出:
1
2
OverloadDefinitions
-------------------
System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Address(int )
1
2
如您所见,我需要添加“.GetEnumerator()”以获得正确的 "address" 值。
这是预期的吗?为了安全起见,我应该始终使用“.GetEnumerator()”吗?
因为 $list
是一个 array (集合),使用 $list.id
执行 member-access enumeration;也就是说,.id
属性 在每个元素 上自动访问 ,结果值作为数组返回 ([object[]]
)[1].
但是,如果数组/集合类型本身 有一个该名称的成员(属性 或方法),它 优先 ,这就是你的情况:.NET 数组有一个 .Address
方法(由运行时添加 - 参见 this answer),这就是抢占访问 元素的 .Address
属性.
(您看到的是 PowerShell 对方法签名(重载)的表示,这是您仅通过名称访问方法时得到的结果,而不是通过附加 ((...)
) 实际调用它);试试 'foo'.ToUpper
,例如。)
解决该问题的最有效方法是使用 PSv4+ .ForEach()
数组方法,该方法始终针对集合的 元素:
$list = '[{"id":"1","address":"1"},{"id":"2","address":"2"}]' | ConvertFrom-Json
$list.ForEach('address')
警告:如果您是 运行 Windows PowerShell 和 $list
在某些情况下只能导致 单个 pscustomobject
而不是 数组 ,您必须 将数组子表达式运算符@(...)
中的$list
括起来,以确保.ForEach()
方法可用。这是一个 [pscustomobject]
-specific bug(假设即使是单个对象也应该始终有一个 .ForEach()
方法),它已在 PowerShell (Core) 6+.中修复。
# @(...) is necessary in Windows PowerShell only.
@($list).ForEach('address')
注:
从技术上讲,这个 returns 是一个
[System.Collections.ObjectModel.Collection[PSObject]]
集合,但在大多数情况下,您可以像使用常规[object[]]
PowerShell 数组一样使用它。与成员访问枚举不同,如果输入集合中只有 一个 元素,也会返回一个集合实例(而不是返回该元素的 属性 值原样,成员访问枚举的方式)。
在 PSv3- 中,您可以使用 ForEach-Object
cmdlet,或 Select-Object -ExpandProperty
:
$list | ForEach-Object address # PSv2: | ForEach-Object { $_.address }
# OR
$list | Select-Object -ExpandProperty address
[1] 如果集合中只有 one 元素,则其 属性 值按原样返回,不包含在 (单元素)数组,这与在变量中收集 pipeline 输出时应用的逻辑相同。 GitHub issue #6802.[=37= 中讨论了这种逻辑在 表达式 上下文的成员访问枚举的上下文中可能是意外的]