Powershell与.NET中的Newtonsoft Json Linq存在问题?
我在C#.NET应用程序中有以下代码Powershell与.NET中的Newtonsoft Json Linq存在问题?,powershell,json.net,Powershell,Json.net,我在C#.NET应用程序中有以下代码 JObject myJObject = new JObject(); JArray myJArray = new JArray(); myJObject.Add( (new JProperty("PropA", (new JObject(new JProperty("PropA1", ""))))) ); Console.WriteLine(myJObject.ToString());
JObject myJObject = new JObject();
JArray myJArray = new JArray();
myJObject.Add(
(new JProperty("PropA", (new JObject(new JProperty("PropA1", "")))))
);
Console.WriteLine(myJObject.ToString());
它按预期工作,我得到的输出是
{
“PropA”:{
“1”:”
}
}
然而,当我在powershell中执行完全相同的代码时(但已翻译)
它爆炸了,我得到了错误
新对象:异常调用带有“1”参数的“.ctor”:“无法将Newtonsoft.Json.Linq.JValue添加到Newtonsoft.Json.Linq.JObject。”
有趣的是,如果我使用相同的代码,但添加了两个属性,它就可以工作了
$myJObject.Add(
(New-Object JProperty("PropA",(New-Object JObject((New-Object JProperty("PropA1","")), (New-Object JProperty("PropA2",""))))))
)
但我当然明白了
{
“PropA”:{
“1”:“1”,
“2”:”
}
}
我做错了什么?我怀疑出于某种原因,PowerShell没有解析正确的
JObject
构造函数,尽管我不知道为什么。我用你的例子玩了一段时间,无法说服PowerShell做正确的事情
我建议重写脚本,以便使用空构造函数创建JObjects
,然后使用Add
方法向它们添加属性。我能够通过以下方式获得您想要的输出:
$emptyVal = New-Object JValue ""
$innerObject = New-Object JObject
$innerObject.Add("PropA1", $emptyVal)
$myJObject = New-Object JObject
$myJObject.Add("PropA", $innerObject)
Write-Host $myJObject.ToString()
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+static:new()
方法:
[JObject] $myJObject = New-Object JObject
$myJObject.Add(
[JProperty]::new("PropA",
[JObject]::new(
# No workaround needed.
[JProperty]::new("PropA1", "")
)
)
)
$myJObject.ToString()
New-Object JObject (, (New-Object JProperty "PropA1", "")) # OK - wrapped in array
在正确的轨道上:问题是内部
JObject
构造函数在使用New Object
cmdlet调用时没有接收作为参数传递的JProperty
实例
# *Seemingly* the equivalent of: new JObject(new JProperty("PropA1", ""))
New-Object JObject (New-Object JProperty "PropA1", "") # !! FAILS
注意使用类似shell的语法-空格分隔的参数,参数列表周围没有括号-因为这是像New Object
这样的cmdlet所期望的-这些不是方法调用;它们是在中解析的PowerShell命令
将JProperty
实例包装到助手数组中,解决了该问题:
[JObject] $myJObject = New-Object JObject
$myJObject.Add(
[JProperty]::new("PropA",
[JObject]::new(
# No workaround needed.
[JProperty]::new("PropA1", "")
)
)
)
$myJObject.ToString()
New-Object JObject (, (New-Object JProperty "PropA1", "")) # OK - wrapped in array
,
是PowerShell的数组构造操作符,因此,,
创建单个元素对象[]
数组,包装
的结果[1]
但是,通过使用PSv5+静态::new()
构造方法可以避免问题<代码>::new()可用于所有类型,并允许您使用方法语法调用构造函数:
关于标量
JProperty
参数不能与PowerShell中的新对象一起工作的原因
:
[JObject] $myJObject = New-Object JObject
$myJObject.Add(
[JProperty]::new("PropA",
[JObject]::new(
# No workaround needed.
[JProperty]::new("PropA1", "")
)
)
)
$myJObject.ToString()
New-Object JObject (, (New-Object JProperty "PropA1", "")) # OK - wrapped in array
由于JProperty
类型实现了IEnumerable
接口,因此PowerShell在绑定到(隐含的)-ArgumentList
参数(本身就是对象[]
-typed)时,会尝试枚举单个JProperty
实例,而不是将其作为自身传递。这会失败,因为
JObject
构造函数随后会看到该枚举的结果,即表示JSON属性值的JValue
实例,并且不允许从JValue
实例构造JObject
实例,如错误消息所示-请参阅
将这样一个实例包装到数组中可以绕过这个问题:它可以防止JProperty
实例的枚举,并安全地将其传递到辅助对象[]
实例中
如果要传递给新对象JObject
的是一个数组,例如传递两个JProperty
实例的示例,那么问题也可以避免
还要注意,强制转换到[JObject]
也可以,但只能使用一个属性:
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] 请注意,
@(…)
,数组子表达式操作符在这种情况下不能正常工作,因为它在将结果包装到[object[]
数组之前也涉及到JProperty
实例的不必要枚举:
# !! 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)
奇怪的是,如果您直接将新对象
调用放在其中,您就可以逃脱@(…)
:
在这种情况下,
@(…)
阻止枚举是因为命令输出(例如,@(新对象…
)-与表达式输出(例如,@($var)
)相反,@(…)
)没有枚举;也就是说,如果命令输出可枚举的内容/作为一个整体的集合-这是新对象在实例化此类类型时所做的操作-@(…)
将其包装为单个元素[Object[]
数组。(顺便说一句:$(…)
将导致枚举)。谢谢您的尝试。我很高兴你看到了和我一样的事情,因为有时候我觉得我疯了!我发现的另一个解决方法是添加这两个属性,以便获得正确的重载,然后返回并删除第二个属性,这样最终结果就是我想要的。