繼承自List的類經過NewtonJson的序列化問題

啥問題呀?

NewtonSoft.Json是咱們最經常使用的Json組件庫之一了。這裏來討論下使用NewtonSoft.Json序列化List<T>子類的情景。序列化使用了類JsonSerializergit

情景重現

若是咱們有一個Field實體類。另有一個FieldGroup類表示Field的分組,並攜帶組屬性GroupFormat。咱們須要序列化這個FieldGroup,該如何實現呢?github

機智如我,這麼寫了:json

// FieldGroup 實現類
public class FieldGroup : List<Field>
{
    public Format GroupFormat{ get;set; }
}

// 序列化過程
public void main()
{
    var group = new FieldGroup()
    {
        GroupFormat = "Format 1"
    };
    group.Add(new Field()
    {
        Name = "Field 1"
    });

    Console.WriteLine(JsonUtil.SerializeByNsj(group));
}

結果我很納悶兒,GroupFormat屬性被JsonSerializer吃了嗎?ide

[
    {
        "Name": "Field 1"
    }
]

咋解決呢?

既然JsonSerializer不會本身處理這個GroupFormat屬性,那我來告訴你它是必需要序列化的!咱們使用[JsonObject(MemberSerialization.OptOut)]來標記這個類除了顯示地標記了[JsonIgnore]特性的公有屬性都須要被序列化。this

[JsonObject(MemberSerialization.OptOut)]
public class FieldGroup : List<Field>
{
    public string Format { get; set; }
}

這下好了吧?emmmmmmm......3d

{
    "Format": "Format 1",
    "Capacity": 4,
    "Count": 1
}

神(NewtonSoft.Json)吶!你又把List吃了嗎!我該拿你怎樣昂昂昂昂昂昂......
固然是,這樣:code

[JsonObject(MemberSerialization.OptOut)]
public class FieldGroup : IEnumerable<Field>
{
    public PrintFormat GroupFormat { get; set; } = new PrintFormat();
    // 使用內部的 List<Field> 代替繼承,可直接被序列化和反序列化
    public List<Field> Fields { get; set; } = new List<Field>();
    // 使用索引對外提供相似於List<T>的訪問方式;
    public Field this[int index]
    {
        get => Fields[index];
        set => Fields[index] = value;
    }
    // 提供List<T>一致的Add方法,有須要能夠提供其餘方法
    public void Add(Field field)
    {
        Fields.Add(field);
    }
    // 提供相似於List<T>的IEnumerable功能
    public IEnumerator<Field> GetEnumerator()
    {
        return new FieldEnumerator(Fields);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

此次的結果是?orm

{
    "Fields": [
        {
            "Name": "Field 1"
        }
    ],
    "Format": "Format 1"
}

老外有話說

Is there any way to JSON.NET-serialize a subclass of List that also has extra properties? blog

public class LocationListJsonConverter : JsonConverter
{
    public override bool CanConvert(System.Type objectType)
    {
        return objectType == typeof(LocationList);
    }

    public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer)
    {
        var locationList = (existingValue as LocationList) ?? new LocationList();
        var jLocationList = JObject.ReadFrom(reader);

        locationList.IsExpanded = (bool)(jLocationList["IsExpanded"] ?? false);

        var jLocations = jLocationList["_Items"];
        if(jLocations != null)
        {
            foreach(var jLocation in jLocations)
            {
                var location = serializer.Deserialize<Location>(new JTokenReader(jLocation));
                locationList.Add(location);
            }
        }
        return locationList;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var locationList = value as LocationList;
        JObject jLocationList = new JObject();
        if(locationList.IsExpanded)
            jLocationList.Add("IsExpanded", true);
        if(locationList.Count > 0)
        {
            var jLocations = new JArray();
            foreach(var location in locationList)
            {
                jLocations.Add(JObject.FromObject(location, serializer));
            }
            jLocationList.Add("_Items", jLocations);
        }
        jLocationList.WriteTo(writer);
    }
}

個人博客園:https://www.cnblogs.com/liwuqingxin/繼承

個人我的站:https://liwuqingxin.github.io/

相關文章
相關標籤/搜索