如何使用Json.Net序列化/反序列化具有其他属性的自定义集合

Pie*_* SS 21 .net c# serialization json json.net

我有一个自定义集合(实现IList),它有一些自定义属性,如下所示:

class FooCollection : IList<Foo> {

    private List<Foo> _foos = new List<Foo>();
    public string Bar { get; set; }        

    //Implement IList, ICollection and IEnumerable members...

}
Run Code Online (Sandbox Code Playgroud)

当我序列化时,我使用以下代码:

JsonSerializerSettings jss = new JsonSerializerSettings() {
    TypeNameHandling = TypeNameHandling.Auto
};
string serializedCollection = JsonConvert.SerializeObject( value , jss );
Run Code Online (Sandbox Code Playgroud)

它正确地序列化和反序列化所有收集项目; 但是,FooCollection不考虑课堂上的任何额外属性.

无论如何将它们包含在序列化中?

dig*_*All 22

问题如下:当一个对象实现时IEnumerable,JSON.net将其标识为值数组,并按照数组Json语法(不包括属性)将其序列化,例如:

 [ {"FooProperty" : 123}, {"FooProperty" : 456}, {"FooProperty" : 789}]
Run Code Online (Sandbox Code Playgroud)

如果要保留属性的序列化,则需要通过定义自定义来手动处理该对象的序列化JsonConverter:

// intermediate class that can be serialized by JSON.net
// and contains the same data as FooCollection
class FooCollectionSurrogate
{
    // the collection of foo elements
    public List<Foo> Collection { get; set; }
    // the properties of FooCollection to serialize
    public string Bar { get; set; }
}

public class FooCollectionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(FooCollection);
    }

    public override object ReadJson(
        JsonReader reader, Type objectType, 
        object existingValue, JsonSerializer serializer)
    {
        // N.B. null handling is missing
        var surrogate = serializer.Deserialize<FooCollectionSurrogate>(reader);
        var fooElements = surrogate.Collection;
        var fooColl = new FooCollection { Bar = surrogate.Bar };
        foreach (var el in fooElements)
            fooColl.Add(el);
        return fooColl;
    }

    public override void WriteJson(JsonWriter writer, object value, 
                                   JsonSerializer serializer)
    {
        // N.B. null handling is missing
        var fooColl = (FooCollection)value;
        // create the surrogate and serialize it instead 
        // of the collection itself
        var surrogate = new FooCollectionSurrogate() 
        { 
            Collection = fooColl.ToList(), 
            Bar = fooColl.Bar 
        };
        serializer.Serialize(writer, surrogate);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用如下:

var ss = JsonConvert.SerializeObject(collection, new FooCollectionConverter());

var obj = JsonConvert.DeserializeObject<FooCollection>(ss, new FooCollectionConverter());
Run Code Online (Sandbox Code Playgroud)


Jef*_*f E 12

就个人而言,我喜欢尽可能避免编写自定义JsonConverters,而是使用为此目的而设计的各种JSON属性.你可以简单的装饰FooCollectionJsonObjectAttribute,这迫使系列化的JSON对象,而不是一个数组.您必须装饰CountIsReadOnly属性JsonIgnore以防止它们出现在输出中.如果你想保留_foos一个私人领域,你也必须用它来装饰它JsonProperty.

[JsonObject]
class FooCollection : IList<Foo> {
    [JsonProperty]
    private List<Foo> _foos = new List<Foo>();
    public string Bar { get; set; }  

    // IList implementation
    [JsonIgnore]
    public int Count { ... }
    [JsonIgnore]
    public bool IsReadOnly { ... }
}
Run Code Online (Sandbox Code Playgroud)

序列化产生如下内容:

{
  "_foos": [
    "foo1",
    "foo2"
  ],
  "Bar": "bar"
}
Run Code Online (Sandbox Code Playgroud)

显然,这只有在您能够更改定义FooCollection以便添加这些属性时才有效,否则您必须采用自定义转换器的方式.

  • 我认为你可以通过显式实现接口来避免“JsonIgnore”。 (2认同)