【问题标题】:Powershell showing wrong output for JSON-object and ADDRESS-propertyPowershell 显示 JSON-object 和 ADDRESS-property 的错误输出
【发布时间】:2020-03-29 04:47:40
【问题描述】:

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

这是一个简单的演示,例如属性“地址”似乎有点特殊:

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()”吗?

【问题讨论】:

  • Address 解析为 Address 包含在 $list 中的数组的属性 - 改为使用 $list|% address

标签: json powershell convertfrom-json member-enumeration


【解决方案1】:

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

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

(您看到的是 PowerShell 对方法签名(重载)的表示,这是您仅通过名称访问方法时得到的,而实际上没有通过附加 ((...)) 来调用它;尝试'foo'.ToUpper,fo实例。)

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] 特有的错误(假设即使是单个对象也应该始终具有 .ForEach() 方法),已在 PowerShell(核心) 6+.

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

注意:

  • 从技术上讲,这会返回一个 [System.Collections.ObjectModel.Collection[PSObject]] 集合,但在大多数情况下,您可以像使用常规的 [object[]] PowerShell 数组一样使用它。

  • 与成员枚举不同,如果输入集合中只有 一个 元素,也会返回一个集合实例(而不是像成员枚举那样按原样返回一个元素的属性值)。


PSv3- 中,您可以使用 ForEach-Object cmdletSelect-Object -ExpandProperty

$list | ForEach-Object address # PSv2: | ForEach-Object { $_.address }
# OR
$list | Select-Object -ExpandProperty address

[1] 如果集合中只有一个一个元素,则其属性值按原样返回,不包装在(单元素)数组中,同理在变量中收集 管道 输出时应用。 this GitHub issue 正在讨论这个逻辑在成员枚举的上下文中可能是出乎意料的,这是一个 表达式 上下文。

【讨论】:

    猜你喜欢
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    相关资源
    最近更新 更多