我尝试编写自己的JsonConverter但由于某种原因它只调用顶级对象,而不是嵌套的PSObjects:
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,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,JsonSerializer serializer) { throw new NotImplementedException(); } public override bool CanRead { get { return false; } } }
笔记:
>在WriteJson
中,将传入的对象值序列化为每个属性的值.当然你的意思是prop.Value
.
>当传入的对象类型是PSObject类型时,仅从CanConvert()
返回true,可以避免在WriteJson()中为非PSObject类型实现默认序列化.
>当您调用JToken.FromObject(value)时,您没有使用传入的JsonSerializer序列化程序.因此,任何JsonSerializerSettings(包括转换器)都将丢失.从理论上讲,您可以使用JToken.FromObject(Object,JsonSerializer)
来保留设置,但如果您这样做,则会遇到JSON.Net throws StackOverflowException when using [JsonConvert()]中描述的错误.幸运的是,由于我们现在在需要默认序列化时从CanConvert返回false,因此不再需要.
>无需构造中间JObject.您可以直接写入JsonWriter,这将更有效.
更新:此外,我正在使用CamelCasePropertyNamesContractResolver序列化到驼峰案例.有没有办法让转换器尊重?
为类型引入custom JsonConverter
后,您需要手动完成所有操作,包括重新映射属性名称.这是WriteJson()的一个版本,使用DefaultContractResolver.NamingStrategy
来处理这个问题:
public override void WriteJson(JsonWriter writer,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中引入的,因此如果您使用的是早期版本,则需要创建自己的驼峰案例名称映射器,如this answer中所示.