在Newtonsoft Json中。. NET自定义JsonConverter
的WriteJson
方法,我可以从JsonConverter
中调用默认的对象序列化行为吗?
也就是说,如果没有注册自定义转换器,我可以推迟序列化吗?
详细信息给定一个Price类
public class Price
{
public string CurrencyCode;
public decimal Amount;
}
正常的Newtonsoft Json。. NET行为是仅当引用为空时才将Price
实例序列化为空。此外,我想在Price.Amount
为零时将Price
实例序列化为null。这是我到目前为止所做的工作(完整的源代码)
public class PriceConverter : JsonConverter
{
// ...
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
var price = (Price)value;
if (0 == price.Amount) {
writer.WriteNull();
return;
}
// I'd like to replace the rest of this method with an appeal to the
// default serialization behavior.
writer.WriteStartObject();
writer.WritePropertyName("amount");
writer.WriteValue(price.Amount);
writer.WritePropertyName("currencyCode");
writer.WriteValue(price.CurrencyCode);
writer.WriteEndObject();
}
// ...
}
这个实现的最后一部分是脆弱的。例如,如果我要向Price
添加字段,我的序列化将被破坏(并且我不知道编写测试来检测这种破坏的好方法)。
我的序列化器有许多行为,通过JsonSerializerSettings在一个单独的程序集中配置,我需要保留这些行为(例如,骆驼大小写属性名)。我不可能在这两者之间添加直接依赖关系。实际上,我使用[JsonConverter(typeof(PriceConverter))]
属性来指定我的自定义转换器应该用于Price
。
有一个解决方法可以让转换器接收设置——您可以使用序列化上下文。
设置:
var settings = new JsonSerializerSettings { /*...*/ };
settings.Context = new StreamingContext(StreamingContextStates.All, settings);
在转换器
:
var settings = (JsonSerializerSettings)serializer.Context.Context;
我做的时候感觉很脏
这种方法有什么问题?
public static JsonSerializerSettings MySettings()
{
return new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
TypeNameHandling = TypeNameHandling.All,
DefaultValueHandling = DefaultValueHandling.Ignore,
DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
};
}
在你的PriceConverter
:
if (0 == price.Amount)
{
writer.WriteNull();
return;
}
else
{
writer.WriteRaw(JsonConvert.SerializeObject(value, Somewhere.MySettings()));
return;
}
在你的程序中:
public static void Custom(Price p)
{
var settings = Somewhere.MySettings();
settings.Converters = new List<JsonConverter> { new PriceConverter() };
Console.WriteLine("custom: " +
JsonConvert.SerializeObject(p, settings));
}