添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
什么问题?

NewtonSoft.Json是我们最常用的Json组件库之一了。这里来讨论下使用NewtonSoft.Json序列化List子类的情景。序列化使用了类JsonSerializer。

情景重现

如果我们有一个Field实体类。另有一个FieldGroup类表示Field的分组,并携带组属性GroupFormat。我们需要序列化这个FieldGroup,该如何实现呢?

机智如我,这么写了:

// FieldGroup 实现类
public class FieldGroup : List{
    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吃了吗?

[
        "Name": "Field 1"
]
咋解决呢?

既然JsonSerializer不会自己处理这个GroupFormat属性,那我来告诉你它是必须要序列化的!我们使用JsonObject(MemberSerialization.OptOut)来标记这个类除了显示地标记了JsonIgnore特性的公有属性都需要被序列化。

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

这下好了吧?emmmmmmm......

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

!!!又把List吃了吗?

原因分析

这点也是在StackOverflow上看到的。Json数组本身就是纯数组,并不能在数组上应用一个属性。

我的解决方法

既然Json不能支持带属性的数组,那只能在代码里面通过索引模拟一个类似于集合的类了。

[JsonObject(MemberSerialization.OptOut)]
public class FieldGroup : IEnumerable{
    public PrintFormat GroupFormat { get; set; } = new PrintFormat();
    // 使用内部的 List代替继承,可直接被序列化和反序列化
    public ListFields { get; set; } = new List();
    // 使用索引对外提供类似于List的访问方式;
    public Field this[int index]
        get => Fields[index];
        set => Fields[index] = value;
    // 提供List一致的Add方法,有需要可以提供其他方法
    public void Add(Field field)
        Fields.Add(field);
    // 提供类似于List的IEnumerable功能
    public IEnumeratorGetEnumerator()
        return Fields.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator()
        return GetEnumerator();
}

这次的结果是?

{
    "Fields": [
            "Name": "Field 1"
    "Format": "Format 1"
}
老外有话说

Is there any way to JSON.NET-serialize a subclass of List

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(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);
                            
enum java 如何 键值 enum java用法

用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。 public enum Color { RED, GREEN, BLANK, YELLOW public enum Color { RED, GREEN, BLANK, YE