继承自List<T>的类通过NewtonJson的序列化问题
什么问题?
NewtonSoft.Json是我们最常用的Json组件库之一了。这里来讨论下使用NewtonSoft.Json序列化List<T>子类的情景。序列化使用了类JsonSerializer。
情景重现
如果我们有一个Field实体类。另有一个FieldGroup类表示Field的分组,并携带组属性GroupFormat。我们需要序列化这个FieldGroup,该如何实现呢?
机智如我,这么写了:
// 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吃了吗?
[
{
"Name": "Field 1"
}
]
咋解决呢?
既然JsonSerializer不会自己处理这个GroupFormat属性,那我来告诉你它是必须要序列化的!我们使用JsonObject(MemberSerialization.OptOut)来标记这个类除了显示地标记了JsonIgnore特性的公有属性都需要被序列化。
[JsonObject(MemberSerialization.OptOut)]
public class FieldGroup : List<Field>
{
public string Format { get; set; }
}
这下好了吧?emmmmmmm......
{
"Format": "Format 1",
"Capacity": 4,
"Count": 1
}
!!!又把List吃了吗?
原因分析
这点也是在StackOverflow上看到的。Json数组本身就是纯数组,并不能在数组上应用一个属性。
我的解决方法
既然Json不能支持带属性的数组,那只能在代码里面通过索引模拟一个类似于集合的类了。
[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 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 that also has extra properties?
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);
}
}
继承自List<T>的类通过NewtonJson的序列化问题的更多相关文章
- 【转载】 C++多继承中重写不同基类中相同原型的虚函数
本篇随笔为转载,原文地址:C++多继承中重写不同基类中相同原型的虚函数. 在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: ...
- 自定义继承于Page的基类
自定义继承于Page的基类:MyBasePage[校验用户是否登录,如果登录则获取用户信息,否则跳转到登录页面]============================================ ...
- 面向对象编程(九)——面向对象三大特性之继承以及重写、Object类的介绍
面向对象三大特性 面向对象三大特征:继承 :封装/隐藏 :多态(为了适应需求的多种变化,使代码变得更加通用!) 封装:主要实现了隐藏细节,对用户提供访问接口,无需关心方法的具体实现. 继承:很好的实现 ...
- 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换
一.不能自动继承的成员函数 构造函数 析构函数 =运算符 二.继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造函数. 声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类 ...
- python之继承、抽象类、新式类和经典类
一.上节补充1.静态属性静态属性 : 类的属性,所有的对象共享这个变量 如果用对象名去修改类的静态属性:在对象的空间中又创建了一个属性,而不能修改类中属性的值 操作静态属性应该用类名来操作 例1:请你 ...
- 第四百零六节,自定义用户表类来继承Django的用户表类,
第四百零六节,自定义用户表类来继承Django的用户表类, models.py from django.db import models # Create your models here. from ...
- Python类总结-继承-子类和父类,新式类和经典类
子类和父类 class Father(object): #子类在使用super调用父类时,Father后面要加object --新式类 def __init__(self): self.Fname = ...
- C++ 类的继承六(多继承的二义性--虚基类)
//多继承的二义性--虚基类(了解为主) #include<iostream> using namespace std; /* 多继承在现在的项目开发中一般不使用,他会增加项目的复杂度 * ...
- 谈谈java中静态变量与静态方法在有继承关系的两个类中调用
谈谈java中静态变量与静态方法在有继承关系的两个类中调用 学习的中如果遇到不明白或者不清楚的的时候,就是自己做些测试,自己去试试,这次我就做一个关于静态变量和静态方法在有继承关系的两个类中的问题测试 ...
随机推荐
- stat filename
查看文件的mtime,atime,ctime 3个时间
- 代码审计 - BugkuCTF
extract变量覆盖: 相关函数: extract()函数:从数组中将变量导入到当前的符号表.把数组键名作为变量名,数组的键值作为变量值.但是当变量中有同名的元素时会默认覆盖掉之前的变量值. tri ...
- 让 Mongoose 不再重复链接数据库(如何正确连接以解决升级后的报错)
升级了 Mongoose 后,发现项目打不开了.报错: MongooseError: You can not `mongoose.connect()` multiple times while con ...
- h5-video,视频在微信里变形、有黑边
如这种情况: 微信可谓是video标签的重灾区,如果你兼容了安卓的微信,那么在其他浏览器一般也没问题了除了个别(IE:你们看我干吗?). 解决方案: <video src="video ...
- [usaco2010 Oct]Soda Machine
题目描述 有N个人要去膜拜JZ,他们不知道JZ会出现在哪里,因此每个人有一个活动范围,只要JZ出现在这个范围内就能被膜拜, 伟大的JZ当然希望膜拜他的人越多越好,但是JZ不能分身,因此只能选择一个位置 ...
- Android根据pdf模板生成pdf文件
我们需要生成一些固定格式的pdf文件或者一些报表数据,那么我们可以用 iText包去做. 需要包含的jar包:iText-5.0.6.jar iTextAsian.jar ,怎样jar包导入工程 ...
- python的零碎知识
1.Python代码操作git 安装 pip3 install gitpython 操作git import os from git.repo import Repo # gitpython def ...
- 01. struts2介绍
struts2优点 与Servlet API 耦合性低.无侵入式设计 提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能 支持多种表现层技术,如:JSP.freeMarker.veloc ...
- Scrapy——將爬取圖片下載到本地
1. Spider程序: 1 import scrapy, json 2 from UnsplashImageSpider.items import ImageItem 3 4 class Unspl ...
- Redis二进制安全
为了便于理解,举一个例子: 在很多编辑器中,都会默认/n是换行字符,也就意味着一串字符存进去,涉及/n都会做一个默认的转义处理,这在编辑语言中,C也有这个特性,例如字符串Hello,\0 World! ...