2012-05-24 23 views
7

Tôi cókỳ quặc sử dụng newtonsoft json.net với PowerShell

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

sau đó làm

foo "a" "b" 

tôi nhận được

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

tuy nhiên

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

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

hoạt động tốt. Cũng

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

foo3 "a" "b" 

công trình nhưng

foo3 "a" 1 

không

Sau đó có thể được thực hiện để làm việc bằng cách làm

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

Mà tất cả dường như rất kỳ quặc

PowerShell v2 trên cửa sổ s 7, json.net 4.4.5

+1

Đó là một bộ thú quan sát, nhưng tôi không chắc chắn câu hỏi của bạn là gì Bạn đang cố gắng đạt được điều gì? –

+0

Tôi khá chắc chắn rằng câu trả lời của tôi thực sự giải quyết vấn đề của bạn mà không yêu cầu thay đổi trong thư viện/v.v ... Nhưng tôi không thấy nhận xét nào về câu trả lời của tôi, cũng như phân bổ tiền thưởng cho câu trả lời của tôi. – Peter

Trả lời

2

Vấn đề về vòng lặp tham chiếu tự đề cập đến .... thứ tự mà bạn chỉ định mọi thứ. Ví dụ dưới đây hoạt động:

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"} 

Nếu bạn chuyển đổi các loại trước khi bạn vượt qua nó trong sau đó nó sẽ giữ chức năng foo3 bạn chung:

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

tôi thực sự muốn có một lời giải thích về những gì đang xảy ra, tôi đã có một vòng làm việc, nhưng vẫn có điểm – pm100

9

JavaScriptSerializer từ khuôn khổ .NET cũng có vấn đề tương tự với việc nối tiếp chuỗi băm của PowerShell. Tôi nghi ngờ nó hơi lạ trong hệ thống kiểu PowerShell. Bạn có thể bỏ qua Json.Net hoàn toàn và cuộn của riêng bạn.

Dưới đây là một số thứ để bạn bắt đầu. Nó có thể không mạnh mẽ như PowerShell 3 được xây dựng trong ConvertTo-Json cmdlet, nhưng tôi nghĩ rằng nó là chủ yếu là hoàn thành.

Dưới đây là tất cả ví dụ của bạn, theo thứ tự làm việc.

# 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} 

Và đây là mô-đun PowerShell triển khai ConvertTo-Json.

# 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

nhận thấy trường hợp tôi gán một biến có giá trị là 1 và thất bại, nhưng nếu tôi chuyển đổi nó thành một chuỗi và sau đó chuyển nó trở lại thành int nó hoạt động tốt. Không có băm có liên quan ở đây – pm100

+0

@ pm100 Vâng, tôi đã thấy điều đó. Bạn vẫn gán giá trị được chuyển đổi theo cách thủ công thành '$ o.B' và' $ o' thực sự là một băm. Giải pháp của tôi sẽ cho phép bạn thực hiện điều đó mà không yêu cầu người gọi thực hiện kiểm tra thủ công trên bất kỳ giá trị nào bạn cần chuyển đổi hoặc xây dựng đối tượng nguồn theo bất kỳ cách cụ thể nào. –

+0

@ pm100 Tôi vừa thêm hỗ trợ cho các đối tượng và PSObject, do đó bạn thậm chí không cần phải sử dụng băm nữa nếu bạn không muốn. –

Các vấn đề liên quan