Powershell显示JSON对象和地址属性的错误输出

Powershell显示JSON对象和地址属性的错误输出,json,powershell,convertfrom-json,member-enumeration,Json,Powershell,Convertfrom Json,Member Enumeration,我目前正在努力将JSON字符串转换为对象数组,并处理每个对象的属性 下面是一个简单的演示,它显示了例如属性“address”似乎有点特殊: cls $json = '[{"id":"1","address":"1"},{"id":"2","address":"2"}]' $list = $json | ConvertFrom-Json $list.id # OK $list.address # gives a weire

我目前正在努力将JSON字符串转换为对象数组,并处理每个对象的属性

下面是一个简单的演示,它显示了例如属性“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()”以获得正确的“地址”值


这是预期的吗?我是否应该始终使用“.GetEnumerator()”以确保安全?

因为
$list
是一个数组(集合),使用类似
$list.id
的东西执行;也就是说,在每个元素上自动访问
.id
属性,结果值作为数组返回(
[object[]]
)[1]

但是,如果数组/集合类型本身有一个同名的成员(属性或方法),则它优先于,这就是您的情况:.NET数组有一个
.Address
方法(由运行时添加-请参阅),这就是抢占访问元素的
.Address
属性的原因

(您看到的是PowerShell对方法签名(重载)的表示,这是当您仅按名称访问方法,而不通过附加(
(…)
)实际调用它时得到的;请尝试
'foo'.ToUpper
,例如)

PowerShell没有提供明确的运算符语法来区分直接成员访问和成员枚举,这是[GitHub issue#7445]的主题(https://github.com/PowerShell/PowerShell/issues/7445),但现有的行为不太可能改变。 解决该问题的最有效方法是使用PSv4+数组方法,该方法始终以集合的元素为目标:

注意事项:如果运行的是Windows PowerShell
$list
可能会在某种情况下生成单个
pscustomobject
而不是数组,则必须
$list
括在数组子表达式操作符
@(…)
中,以确保
.ForEach()
方法可用。这是一个特定于
[pscustomobject]
的bug
(考虑到即使是单个对象也应该始终有一个
.ForEach()
方法),它已在PowerShell(Core)6+
中得到修复

# @(...) is necessary in Windows PowerShell only.
@($list).ForEach('address')
注:

  • 从技术上讲,这将返回一个
    [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] 如果集合中只有一个元素,则其属性值按原样返回,而不是包装在(单个元素)数组中,这与在变量中收集管道输出时应用的逻辑相同。此逻辑在成员枚举的上下文中可能是意外的,这是一个表达式上下文,在中讨论。

Address
解析为
$list
-do
$list |%Address
中包含的数组的
Address
属性
$list | ForEach-Object address # PSv2: | ForEach-Object { $_.address }
# OR
$list | Select-Object -ExpandProperty address