2012-05-24 20 views
7

tengorareza usando newtonsoft json.net con PowerShell

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

luego hacer

foo "a" "b" 

consigo

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

embargo

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

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

funciona bien. También

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

foo3 "a" "b" 

obras, sino

foo3 "a" 1 

falla

Este último se puede hacer para trabajar haciendo

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

cual todo parece muy extraño

PowerShell v2 en ventana s 7, json.net 4.4.5

+1

Eso es un interesante conjunto de observaciones, pero no estoy seguro cuál es tu pregunta ¿Qué estás intentando lograr? –

+0

Estoy bastante seguro de que mi respuesta realmente resolvió su problema sin requerir un cambio en la biblioteca/etc ... Pero no vi ningún comentario sobre mi respuesta, ni una asignación de recompensa a mi respuesta. – Peter

Respuesta

2

La cuestión del bucle de autoreferencia parece ser ... el orden en el que se asignan las cosas. El siguiente ejemplo funciona:

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

Si convierte el tipo antes de pasarlo en la entonces mantendrá su función foo3 genérica:

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

en realidad quería una explicación de lo que estaba pasando, ya tengo una ronda de trabajo, pero tengo los puntos de todos modos – pm100

9

El JavaScriptSerializer del .NET framework también tiene un problema similar con la serialización de hashes de PowerShell. Sospecho que es algo extraño en el sistema de tipo PowerShell. Puede omitir Json.Net por completo y hacer su propia versión.

A continuación, algo para comenzar. Es probable que no sea tan robusto como el cmdlet incorporado de PowerShell 3 ConvertTo-Json, pero creo que está casi completo.

Aquí están todos de sus ejemplos, en buen estado.

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

Y aquí está el módulo de PowerShell que implementa 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

observe el caso donde asigno una variable cuyo valor es 1 y que falla, pero si lo convierto en una cadena y luego lo vuelvo a convertir a una int, funciona bien. Sin hashes involucrados aquí – pm100

+0

@ pm100 Sí, lo vi. Todavía está asignando el valor convertido manualmente a '$ o.B' y' $ o' es de hecho un hash. Mi solución le permitirá hacerlo sin requerir que la persona que realiza la llamada realice una comprobación manual de los valores que necesita para convertir o crear el objeto fuente de alguna manera en particular. –

+0

@ pm100 Acabo de agregar compatibilidad para objetos y PSObjects para que no tenga que usar hashes más si no lo desea. –

Cuestiones relacionadas