2012-05-24 20 views
7

怪胎使用newtonsoft json.net使用PowerShell

function Foo($a, $b) 
{ 
    $o = @{} 
    $o.A = $a 
    $o.B = $b 
    $post = @{} 
    $post.X="x" 
    $post.entity =$o 
    $newton::SerializeObject($post) 
} 

然后做

foo "a" "b" 

我得到

Exception calling "SerializeObject" with "1" argument(s): "Self referencing loop detected for property 'Value' with type 'System.Management.Automation.PSParameterizedProperty'. Path 'entity.Members[0]'." 

然而

function Foo2($o) 
{ 
    $post = @{} 
    $post.X="x" 
    $post.entity =$o 
    $newton::SerializeObject($post) 
} 

foo2 @{a="a"; b="b"} 

工作正常。此外

function foo3($a, $b) 
{ 
    $o = @{} 
    $o.A = $a 
    $o.B = $b 
    $newton::SerializeObject($o) 
} 

foo3 "a" "b" 

的作品,但

foo3 "a" 1 

失败

后者可以做出这样做

$o.B= [Int32]::Parse($b.Tostring()) 

这一切似乎很奇怪

的PowerShell v2的上下班窗口s 7,json.net 4.4.5

+1

这是一套有趣的观察,但我不知道你的问题是什么。你想达到什么目的? –

+0

我非常肯定,我的答案实际上解决了您的问题,而不需要更改库/等等......但我没有看到我的答案,也没有看到我的答案中的赏金。 – Peter

回答

2

自引用循环问题sems是所有关于....你分配的顺序。下面的示例工作:

function Foo($a, $b) 
{ 
    $o = @{} 
    $post = @{} 

    $post.entity =$o 

    $o.A = $a 
    $o.B = $b 

    $post.X="x" 

    [Newtonsoft.Json.JsonConvert]::SerializeObject($post) 
} 

Foo "a" "b" 

{"entity":{"A":"a","B":"b"},"X":"x"} 

如果转换类型,你通过它之前那么它会保持你的foo3功能通用:

function foo3($a, $b) 
{ 
    $o = @{} 
    $o.A = $a 
    $o.B = $b 
    [Newtonsoft.Json.JsonConvert]::SerializeObject($o) 
} 


$var2 = [Int32]::Parse((1).Tostring()) 

Foo3 "a" $var2 

{"A":"a","B":1} 
+0

我其实想要解释发生了什么,我已经有一个工作轮了,但总得有点意见 – pm100

9

.NET框架中的JavaScriptSerializer也有序列化PowerShell散列的类似问题。我怀疑它在PowerShell类型系统中有点奇怪。你可以完全跳过Json.Net并自己推出。

下面是一些启动你的东西。它可能不像PowerShell 3的内置ConvertTo-Json cmdlet那样健壮,但我认为它大部分是完整的。

这里有全部你的例子,在工作秩序。

# See below for ConvertTo-Json.psm1 
Import-Module ConvertTo-Json 

function Foo($a, $b) 
{ 
    $o = @{} 
    $o.A = $a 
    $o.B = $b 
    $post = @{} 
    $post.X="x" 
    $post.entity =$o 
    ConvertTo-Json $post 
} 

function Foo2($o) 
{ 
    $post = @{} 
    $post.X="x" 
    $post.entity =$o 
    ConvertTo-Json $post 
} 

function foo3($a, $b) 
{ 
    $o = @{} 
    $o.A = $a 
    $o.B = $b 
    ConvertTo-Json $o 
} 

PS> foo "a" "b" 
{"entity":{"A":"a","B":"b"},"X":"x"} 

PS> foo2 @{a="a"; b="b"} 
{"entity":{"a":"a","b":"b"},"X":"x"} 

PS> foo3 "a" "b" 
{"A":"a","B":"b"} 

PS> foo3 "a" 1 
{"A":"a","B":1} 

这里是实现ConvertTo-Json的PowerShell模块。

# Save these contents to Modules\ConvertTo-Json\ConvertTo-Json.psm1 in your 
# PowerShell documents folder, and load them in your $profile using the 
# "Import-Module ConvertTo-Json" cmdlet. This will make the ConvertTo-Json cmdlet 
# available for use. 

Set-StrictMode -Version Latest 

function convertToJsonNull($InputObject) { 
    "null" 
} 

function convertToJsonArray($InputObject) { 
    $value = ($InputObject | %{ convertToJson $_ }) -join ',' 
    "[$value]" 
} 

function convertToJsonHash($InputObject) { 
    $value = ($InputObject.Keys | %{ 
     $name = $_ | asJsonString 
     $itemValue = convertToJson ($InputObject[$_]) 
     '"{0}":{1}' -f $name, $itemValue 
    }) -join ',' 
    "{$value}" 
} 

function convertToJsonObject($InputObject) { 
    $value = ($InputObject | get-member -membertype *property | %{ 
     $name = $_.Name 
     $value = convertToJson ($InputObject.($name)) 
     '"{0}":{1}' -f ($name | asJsonString), $value 
    }) -join ',' 
    "{$value}" 
} 

function convertToJsonString($InputObject) { 
    '"{0}"' -f ($InputObject | asJsonString) 
} 

function convertToJsonBool($InputObject) { 
    $InputObject.ToString().ToLower() 
} 

function convertToJsonNumeric($InputObject) { 
    "$InputObject" 
} 

function convertToJsonDate($InputObject) { 
    $epoch = [datetime]"1970-01-01T00:00:00Z" 
    $elapsed = [long]($InputObject - $epoch).TotalMilliseconds 
    '"\/Date({0})\/"' -f $elapsed 
} 

filter isNumeric() { 
    $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or 
    $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or 
    $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] 
} 

filter asJsonString { 
    ($_ -replace '\\', '\\') -replace '"', '\"' 
} 

function convertToJson($InputObject) { 
    if  ($InputObject -eq $null)  { convertToJsonNull $InputObject } 
    elseif ($InputObject -is [array])  { convertToJsonArray $InputObject } 
    elseif ($InputObject -is [hashtable]) { convertToJsonHash $InputObject } 
    elseif ($InputObject -is [datetime]) { convertToJsonDate $InputObject } 
    elseif ($InputObject -is [string]) { convertToJsonString $InputObject } 
    elseif ($InputObject -is [char])  { convertToJsonString $InputObject } 
    elseif ($InputObject -is [bool])  { convertToJsonBool $InputObject } 
    elseif ($InputObject | isNumeric)  { convertToJsonNumeric $InputObject } 
    else         { convertToJsonObject $InputObject } 
} 

function ConvertTo-Json { 
    [CmdletBinding()] 
    param(
     [Parameter(
      ValueFromPipeline = $true, 
      ValueFromPipelineByPropertyName = $true 
     )] 
     $InputObject 
    ) 
    convertToJson $InputObject 
} 

Export-ModuleMember -Function ConvertTo-Json 
+0

注意到我指定一个变量的值为1并失败的情况,但是如果我将它转换为一个字符串,然后将它转换回一个int,它工作正常。这里没有涉及的散列 – pm100

+0

@ pm100是的,我看到了。你仍然将手动转换后的值赋给'$ o.B','$ o'确实是一个散列。我的解决方案将允许您这样做,而不需要调用方对任何需要转换的值执行手动检查,或者以任何特定方式构建源对象。 –

+0

@ pm100我刚刚添加了对对象和PSObjects的支持,所以如果你不想使用散列,你甚至不必再使用散列。 –