[英]How can I serialise PSObjects in C# with JSON.NET?
我正在編寫一個Cmdlet,需要將對象結構傳遞給可能包含PSObject
的API客戶端。 目前,這些序列化作為包含CLIXML的JSON字符串。 相反,我需要將它視為一個對象(包括PSObject.Properties
的NoteProperties作為屬性,並遞歸地序列化它們的值)。
我嘗試編寫自己的JsonConverter
但由於某種原因它只調用頂層對象,而不是嵌套的PSObject
:
public class PSObjectJsonConverter : JsonConverter {
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
if (value is PSObject) {
JObject obj = new JObject();
foreach (var prop in ((PSObject)value).Properties) {
obj.Add(new JProperty(prop.Name, value));
}
obj.WriteTo(writer);
} else {
JToken token = JToken.FromObject(value);
token.WriteTo(writer);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
throw new NotImplementedException();
}
public override bool CanRead {
get { return false; }
}
public override bool CanConvert(Type objectType) {
return true;
}
}
此外,我正在使用CamelCasePropertyNamesContractResolver
序列化到駝峰案例。 有沒有辦法讓轉換器尊重?
以下轉換器應正確序列化PSObject
類型的遞歸嵌套對象:
public class PSObjectJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(PSObject).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var psObj = (PSObject)value;
writer.WriteStartObject();
foreach (var prop in psObj.Properties)
{
//Probably we shouldn't try to serialize a property that can't be read.
//https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.pspropertyinfo.isgettable?view=powershellsdk-1.1.0#System_Management_Automation_PSPropertyInfo_IsGettable
if (!prop.IsGettable)
continue;
writer.WritePropertyName(prop.Name);
serializer.Serialize(writer, prop.Value);
}
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanRead { get { return false; } }
}
筆記:
在WriteJson
您將傳入的對象value
序列化為每個屬性的值。 當然你的意思是prop.Value
。
通過僅在傳入對象類型為PSObject
類型時從CanConvert()
返回true
,可以避免在WriteJson()
為非PSObject
類型實現默認序列化。
當您調用JToken.FromObject(value)
您沒有使用傳入的JsonSerializer serializer
。 因此,任何JsonSerializerSettings
(包括轉換器)都將丟失。 理論上你可以使用JToken.FromObject(Object, JsonSerializer)
來保存設置,但是如果你這樣做,你會遇到JSON.Net中描述的bug在使用[JsonConvert()]時拋出StackOverflowException 。 幸運的是,由於我們現在在需要默認序列化時從CanConvert
返回false
,因此不再需CanConvert
。
不需要構造中間JObject
。 您可以直接寫入JsonWriter
,這將更有效。
更新 : 此外,我正在使用CamelCasePropertyNamesContractResolver
序列化到駝峰案例。 有沒有辦法讓轉換器尊重?
為類型引入自定義JsonConverter
,您需要手動執行所有操作,包括重新映射屬性名稱。 這是WriteJson()
的一個版本,它通過使用DefaultContractResolver.NamingStrategy
來處理這個問題:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var psObj = (PSObject)value;
writer.WriteStartObject();
var resolver = serializer.ContractResolver as DefaultContractResolver;
var strategy = (resolver == null ? null : resolver.NamingStrategy) ?? new DefaultNamingStrategy();
foreach (var prop in psObj.Properties)
{
//Probably we shouldn't try to serialize a property that can't be read.
//https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.pspropertyinfo.isgettable?view=powershellsdk-1.1.0#System_Management_Automation_PSPropertyInfo_IsGettable
if (!prop.IsGettable)
continue;
writer.WritePropertyName(strategy.GetPropertyName(prop.Name, false));
serializer.Serialize(writer, prop.Value);
}
writer.WriteEndObject();
}
請注意,命名策略是在Json.NET 9.0.1中引入的,因此如果您使用的是早期版本,則需要創建自己的駝峰案例名稱映射器,如本答案中所示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.