ТЛ; др
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()
Ответ Брайана Роджерса был на правильном пути: проблема в том, что внутренний конструктор JObject
не получает экземпляр JProperty
, передаваемый в качестве аргумента как например при использовании вызовов командлетов New-Object
.
# *Seemingly* the equivalent of: new JObject(new JProperty("PropA1", ""))
New-Object JObject (New-Object JProperty "PropA1", "") # !! FAILS
Обратите внимание на использование подобного оболочке синтаксиса - аргументы, разделенные пробелами, без скобок вокруг списка аргументов - потому что именно этого ожидает командлет, такой как New-Object
- это не вызовы методов; это команды PowerShell, проанализированные в режиме аргумента .
Включение экземпляра JProperty
в вспомогательный массив устраняет проблему :
New-Object JObject (, (New-Object JProperty "PropA1", "")) # OK - wrapped in array
,
- это оператор построения массива PowerShell , поэтому , <expr>
создает одноэлементный массив object[]
, охватывающий результат <expr>
. [1]
Тем не менее, проблемы с можно избежать, если использовать метод PSv5 + static ::new()
для построения ; ::new()
доступен для всех типов и позволяет вызывать конструкторы, используя синтаксис метода :
[JObject]::new([JProperty]::new("PropA1", "")) # OK
Что касается , почему аргумент a scalar JProperty
не работает с New-Object
в PowerShell :
Поскольку тип JProperty
реализует интерфейс IEnumerable
, PowerShell пытается перечислить отдельный экземпляр JProperty
вместо передачи его как самого себя при привязке к (подразумевается) ) -ArgumentList
параметр (который сам object[]
-тип).
Это терпит неудачу, потому что конструктор JObject
затем видит результат этого перечисления, который является JValue
экземпляром, представляющим свойство JSON value , и создающим экземпляр JObject
из экземпляра JValue
isn не разрешено, как отражено в сообщении об ошибке - см. ответ Брайана здесь .
Обтекание такого экземпляра в массиве позволяет обойти проблему: оно предотвращает перечисление экземпляра 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 может быть достаточно, и вы даже можете конвертировать пользовательские объекты / хеш-таблицы в JObject
/ JToken
экземпляры через строковое представление JSON, хотя не дешево:
PS> [JToken]::Parse((@{ PropA = @{ PropA1 = 42 } } | ConvertTo-Json -Compress)).ToString()
{
"PropA": {
"PropA1": 42
}
}
[1] Обратите внимание, что @(...)
, оператор подвыражения массива, не работает надежно в этом случае, поскольку он также включает нежелательное перечисление экземпляра JProperty
перед переносом результата в массив [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 BEST AVOIDED.
# !! Use (, (New-Object JProperty "PropA1", "")) instead.
New-Object JObject @(New-Object JProperty "PropA1", "")
Весьма неясная причина этой счастливой случайности, на которую не следует полагаться, заключается в том, что использование команды вместо выражения напрямую приводит к обычно невидимому дополнительному [psobject]
обертка, которая в этом случае предотвращает перечисление экземпляра JProperty
; общую справочную информацию смотрите в этом выпуске GitHub .