【问题标题】:serialize object as null based on one of its properties根据其属性之一将对象序列化为 null
【发布时间】:2013-06-05 19:41:12
【问题描述】:

在 Newtonsoft Json.NET 自定义 JsonConverterWriteJson 方法中,我可以从 JsonConverter 中上诉默认对象序列化行为吗?

也就是说,如果没有注册自定义转换器,我可以推迟序列化吗?

详情

给定一个价格等级

public class Price
{
    public string CurrencyCode;
    public decimal Amount;
}

正常的 Newtonsoft Json.NET 行为是仅在引用为空时将Price 实例序列化为空。此外,我想在Price.Amount 为零时将Price 实例序列化为null。这是我到目前为止所做的工作 (complete source code)

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

【问题讨论】:

标签: .net json serialization json.net


【解决方案1】:

有一种解决方法可以让转换器接收设置——您可以使用序列化上下文。

设置:

var settings = new JsonSerializerSettings { /*...*/ };
settings.Context = new StreamingContext(StreamingContextStates.All, settings);

在转换器中:

var settings = (JsonSerializerSettings)serializer.Context.Context;

我这样做的时候感觉很脏。

【讨论】:

    【解决方案2】:

    这种方法有什么问题?

    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));
        }
    

    【讨论】:

    • 好问题。我的序列化程序有许多行为,通过 JsonSerializerSettings 在其他地方配置,我需要保留这些行为(例如,驼峰式属性名称)。我将更新问题以包含此信息。
    • 你能把那些behaviors 添加到要点吗?
    • 我添加了一个我试图保留的设置示例。
    • 我不确定这就是你要找的东西(也许我不明白问题的本质),但我修改了我的答案......
    • 另一个好点。设置和Price 类是在单独的程序集中定义的,并且依赖注入考虑使我无法按照您的建议引用全局设置构建器。
    猜你喜欢
    • 1970-01-01
    • 2015-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多