C# Newtonsoft.Json 自定义解串器
C# Newtonsoft.Json Custom Deserializer
我正在使用一个 API 以不同于我过去处理的方式向我返回结果,而且看起来不标准。
例如,这里有一段客户数据:
{
"CustomerID": {
"value": "EXAMPLE"
},
"CustomerCurrencyID": {
"value": "USD"
}
}
那个“值”属性 似乎非常不必要,所以我想看看我是否可以一起绕过它并将 JSON 反序列化为一个对象,如下所示:
class Customer {
public string CustomerID { get; set; }
public string CustomerCurrencyID { get; set; }
}
我目前正在编写一个自定义的 JsonConverter 来处理这个问题,所以如果我正朝着正确的方向前进,请告诉我,但是任何 tips/tricks 这里将不胜感激!
您可以使用如下通用 custom JsonConverter
执行此操作:
public class WrapWithValueConverter<TValue> : JsonConverter
{
// Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
class DTO { [JsonConverter(typeof(NoConverter))] public TValue value { get; set; } public object GetValue() => value; }
public override bool CanConvert(Type objectType) => typeof(TValue).IsAssignableFrom(objectType);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> serializer.Serialize(writer, new DTO { value = (TValue)value });
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
=> serializer.Deserialize<DTO>(reader)?.GetValue();
}
public class NoConverter : JsonConverter
{
// NoConverter taken from this answer
// By https://whosebug.com/users/3744182/dbc
// To
public override bool CanConvert(Type objectType) { throw new NotImplementedException(); /* This converter should only be applied via attributes */ }
public override bool CanRead => false;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}
然后您可以将其应用到您的模型中,如下所示:
class Customer {
[JsonConverter(typeof(WrapWithValueConverter<string>))]
public string CustomerID { get; set; }
[JsonConverter(typeof(WrapWithValueConverter<string>))]
public string CustomerCurrencyID { get; set; }
}
演示 fiddle #1 here.
或者,如果你想所有字符串包装在一个{"value": <string value>}
对象中,你可以在序列化和反序列化时将转换器添加到JsonSerializerSettings.Converters
:
var settings = new JsonSerializerSettings
{
Converters = { new WrapWithValueConverter<string>() },
};
var model = JsonConvert.DeserializeObject<Customer>(json, settings);
var json2 = JsonConvert.SerializeObject(model, Formatting.Indented, settings);
演示 fiddle #2 here.
如果您的值是 enum
并且您想将其序列化为字符串,您可以使用以下命令将 NoConverter
替换为 StringEnumConverter
:
public class WrapEnumWithValueConverter<TEnum> : JsonConverter where TEnum: Enum
{
// Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
class DTO { [JsonConverter(typeof(StringEnumConverter))] public TEnum value { get; set; } public object GetValue() => value; }
public override bool CanConvert(Type objectType) => typeof(TEnum).IsAssignableFrom(objectType);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> serializer.Serialize(writer, new DTO { value = (TEnum)value });
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
=> serializer.Deserialize<DTO>(reader)?.GetValue();
}
演示 fiddle #3 here.
我正在使用一个 API 以不同于我过去处理的方式向我返回结果,而且看起来不标准。
例如,这里有一段客户数据:
{
"CustomerID": {
"value": "EXAMPLE"
},
"CustomerCurrencyID": {
"value": "USD"
}
}
那个“值”属性 似乎非常不必要,所以我想看看我是否可以一起绕过它并将 JSON 反序列化为一个对象,如下所示:
class Customer {
public string CustomerID { get; set; }
public string CustomerCurrencyID { get; set; }
}
我目前正在编写一个自定义的 JsonConverter 来处理这个问题,所以如果我正朝着正确的方向前进,请告诉我,但是任何 tips/tricks 这里将不胜感激!
您可以使用如下通用 custom JsonConverter
执行此操作:
public class WrapWithValueConverter<TValue> : JsonConverter
{
// Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
class DTO { [JsonConverter(typeof(NoConverter))] public TValue value { get; set; } public object GetValue() => value; }
public override bool CanConvert(Type objectType) => typeof(TValue).IsAssignableFrom(objectType);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> serializer.Serialize(writer, new DTO { value = (TValue)value });
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
=> serializer.Deserialize<DTO>(reader)?.GetValue();
}
public class NoConverter : JsonConverter
{
// NoConverter taken from this answer
// By https://whosebug.com/users/3744182/dbc
// To
public override bool CanConvert(Type objectType) { throw new NotImplementedException(); /* This converter should only be applied via attributes */ }
public override bool CanRead => false;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}
然后您可以将其应用到您的模型中,如下所示:
class Customer {
[JsonConverter(typeof(WrapWithValueConverter<string>))]
public string CustomerID { get; set; }
[JsonConverter(typeof(WrapWithValueConverter<string>))]
public string CustomerCurrencyID { get; set; }
}
演示 fiddle #1 here.
或者,如果你想所有字符串包装在一个{"value": <string value>}
对象中,你可以在序列化和反序列化时将转换器添加到JsonSerializerSettings.Converters
:
var settings = new JsonSerializerSettings
{
Converters = { new WrapWithValueConverter<string>() },
};
var model = JsonConvert.DeserializeObject<Customer>(json, settings);
var json2 = JsonConvert.SerializeObject(model, Formatting.Indented, settings);
演示 fiddle #2 here.
如果您的值是 enum
并且您想将其序列化为字符串,您可以使用以下命令将 NoConverter
替换为 StringEnumConverter
:
public class WrapEnumWithValueConverter<TEnum> : JsonConverter where TEnum: Enum
{
// Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
class DTO { [JsonConverter(typeof(StringEnumConverter))] public TEnum value { get; set; } public object GetValue() => value; }
public override bool CanConvert(Type objectType) => typeof(TEnum).IsAssignableFrom(objectType);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> serializer.Serialize(writer, new DTO { value = (TEnum)value });
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
=> serializer.Deserialize<DTO>(reader)?.GetValue();
}
演示 fiddle #3 here.