tl;dr
using namespace Newtonsoft.Json.Linq
Add-Type -Path "C:\Temp\Newtonsoft.Json.dll"
[JObject] $myJObject = New-Object JObject
$myJObject.Add(
(New-Object JProperty "PropA",
(New-Object JObject (
# Note the , (...) around this New-Object call,
# which wraps the resulting JProperty instance in a
# single-element array.
, (New-Object JProperty "PropA1", "")
)
)
)
)
$myJObject.ToString()
替代方法,使用 PSv5+ 静态 ::new() 方法可用于调用构造函数的类型:
[JObject] $myJObject = New-Object JObject
$myJObject.Add(
[JProperty]::new("PropA",
[JObject]::new(
# No workaround needed.
[JProperty]::new("PropA1", "")
)
)
)
$myJObject.ToString()
Brian Rogers' answer 在正确的轨道上:问题在于 内部的 JObject 构造函数没有接收到作为参数传递的 JProperty 实例 strong> 当使用New-Object cmdlet 调用时。
# *Seemingly* the equivalent of: new JObject(new JProperty("PropA1", ""))
New-Object JObject (New-Object JProperty "PropA1", "") # !! FAILS
注意使用 shell-like 语法 - 空格分隔的参数,参数列表周围没有括号 - 因为这是诸如 New-Object 之类的 cmdlet 所期望的 -这些是不是方法调用;它们是在 argument mode 中解析的 PowerShell 命令。
将 JProperty 实例包装在 helper 数组中可以解决问题:
New-Object JObject (, (New-Object JProperty "PropA1", "")) # OK - wrapped in array
, 是 PowerShell 的 数组构造运算符,因此 , <expr> 创建一个包含 <expr> 的结果的单元素 object[] 数组。[1]支持>
不过,这个问题可以通过使用PSv5+静态::new()构造方法一开始就避免; ::new() 适用于所有类型,并允许您使用方法语法调用构造函数:
[JObject]::new([JProperty]::new("PropA1", "")) # OK
至于 为什么 标量 JProperty 参数不适用于 PowerShell 中的 New-Object:
由于JProperty 类型实现了IEnumerable 接口,PowerShell 尝试枚举单个JProperty 实例,而不是将其作为自身传递 (隐含)-ArgumentList 参数(它本身就是object[]-typed)。
这失败了,因为 JObject 构造函数随后看到了该枚举的结果,这是一个代表 JSON 属性 value 的 JValue 实例,并从 JValue 实例构造了一个 JObject 实例不允许,如错误消息中所反映的 - 请参阅Brian's answer here。
将这样的实例包装在一个数组中可以绕过这个问题:它会阻止枚举JProperty 实例并安全地将其传递到辅助object[] 实例中。
如果您传递给New-Object JObject 的是一个数组以开头,例如您传递两个 JProperty 实例的示例,问题还在于避免。
另请注意,转换为 [JObject] 也可以,但仅适用于 one 属性:
New-Object JObject ([JObject] (New-Object JProperty "PropA1", "")) # OK with 1 prop.
并不是说 Powershell 有内置的 JSON 支持,它允许将哈希表和自定义对象方便地转换为 JSON 并返回:
# Convert a nested hashtable to JSON
PS> @{ PropA = @{ PropA1 = 42 } } | ConvertTo-Json -Compress
{"PropA":{"PropA1":42}}
# Convert JSON to a custom object [pscustomobject] with property
# .PropA whose value is another custom object, with property .PropA1
PS> '{"PropA":{"PropA1":42}}' | ConvertFrom-Json
PropA
-----
@{PropA1=42}
因此,除非您有特殊要求和/或性能问题,否则 PowerShell 的内置功能可能就足够了,您甚至可以通过 JSON 字符串表示将自定义对象 / 哈希表转换为 JObject / JToken 实例,尽管不便宜:
PS> [JToken]::Parse((@{ PropA = @{ PropA1 = 42 } } | ConvertTo-Json -Compress)).ToString()
{
"PropA": {
"PropA1": 42
}
}
[1] 请注意,数组子表达式运算符 @(...) 在这种情况下 not 工作得很好,因为它也涉及到不需要的 @987654363 的 枚举 @instance 在将结果包装到 [object[]] 数组之前:
# !! FAILS too:
# The JProperty instance is again enumerated, resulting in a single
# JValue instance, which is what @(...) then wraps in a
# single-element [object[]] array.
$var = New-Object JProperty "PropA1", ""
New-Object JObject @($var)
奇怪的是,你可以摆脱@(...) 如果你直接在其中调用New-Object:
# !! Happens to work, but is OBSCURE.
# !! Equivalent of: (, (New-Object JProperty "PropA1", ""))
New-Object JObject @(New-Object JProperty "PropA1", "")
@(...) 阻止 在这种情况下枚举是由于 command 输出(例如,@(New-Object ...))而不是 表达式 输出(例如,@($var))- 不是由@(...) 枚举的;也就是说,如果命令输出的东西是可枚举的/集合作为一个整体 - 这是 New-Object 在实例化此类类型时所做的 - @(...) 将其按原样包装在单个元素中[object[]] 数组。 (顺便说一句:$(...) 会导致枚举)。