整个类型的Json.NET条件序列化

时间:2015-01-26 09:16:44

标签: c# json json.net

我知道Json.NET支持使用ShouldSerialize{PropName}

进行条件序列化

但有没有办法阻止整个类型被序列化而不改变引用它的类型? e.g。

 public class Foo
 {
     public bool Enabled {get;set;}
     ...other properties
 }

 public class Bar
 {
     public Foo SomeFoo {get;set;}
     public Foo OtherFoo {get;set;}
 }

我希望Bar类型不包括SomeFooo或OtherFoo,具体取决于是否设置了Enabled属性。如果SomeFoo.Enabled = false,则不应序列化Bar.SomeFoo。

所以我想要一个引用属性的条件序列化。 我不希望消费Foo类型有任何额外的代码或属性。它应该全部采用Foo类型。

我可以在Bar中添加一个ShouldSerializeSomeFoo ..但这不是我想要的..

2 个答案:

答案 0 :(得分:2)

您可以编写自定义JsonConverter来处理Foo的序列化。

我在下面写了一个非常基本的版本,但我建议你更深入地研究它。

此版本保留属性引用,只是不序列化对象。您还可以为Bar编写转换器,忽略整个属性。

public class FooJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var foo = value as Foo;
        if (foo == null || !foo.Enabled)
            return;

        writer.WriteStartObject();

        writer.WritePropertyName("Enabled");
        serializer.Serialize(writer, foo.Enabled);

        //Write the rest of the serialization

        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize(reader, objectType);
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (Foo);
    }
}

用法:

var trueFoo = new Foo()
{
    Enabled = true
};

var falseFoo = new Foo()
{
    Enabled = false
};

var bar = new Bar()
{
    SomeFoo = trueFoo,
    OtherFoo = falseFoo
};


//{"SomeFoo":{"Enabled":true},"OtherFoo":null}
var json = JsonConvert.SerializeObject(bar, new FooJsonConverter());

答案 1 :(得分:2)

我认为此问题的最佳解决方案是编写自定义IContractResolver。解析器可以以编程方式将ShouldSerialize方法应用于包含Foo的每个对象,该对象将依次检查Foo实例以查看它是否已启用。如果不是,则该属性根本不会被序列化。

创建解析器的最简单方法是从DefaultContractResolver派生它,然后覆盖CreateProperties方法。以下是您需要的代码:

using System;
using System.Collections.Generic;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

class CustomResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        foreach (JsonProperty prop in properties)
        {
            if (prop.PropertyType == typeof(Foo))
            {
                prop.ShouldSerialize = obj => 
                {
                    Foo foo = (Foo)type.GetProperty(prop.PropertyName).GetValue(obj);
                    return foo != null && foo.Enabled;
                };
            }
        }
        return properties;
    }
}

您可以通过JsonSerializerSettings应用自定义解析器,如下所示:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    ContractResolver = new CustomResolver(),
};
string json = JsonConvert.SerializeObject(objToSerialize, settings);

这是一个完整演示的小提琴:https://dotnetfiddle.net/wnLbyD