继承自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中静态变量与静态方法在有继承关系的两个类中调用 学习的中如果遇到不明白或者不清楚的的时候,就是自己做些测试,自己去试试,这次我就做一个关于静态变量和静态方法在有继承关系的两个类中的问题测试 ...
随机推荐
- 【Linux】Linux基础命令 - 目录相关的命令 ls 、cd、du
文章目录 目录相关的命令 ls 命令:列出文件和目录 cd 命令:切换目录 du 命令:显示目录包含的文件大小 总结 参考资料 巩固和复习Linux系统基础命令知识 目录相关的命令 ls 命令:列出文 ...
- buuctf—web—高明的黑客
打开靶机,看到如下界面 于是打开www.tar.gz 下载后发现是一个放有大量php文件的文件夹 看了大佬的wp后明白了是fuzzing 附上大佬的脚本 import os import re imp ...
- 为什么会有 AtomicReference ?
我把自己以往的文章汇总成为了 Github ,欢迎各位大佬 star https://github.com/crisxuan/bestJavaer 我们之前了解过了 AtomicInteger.Ato ...
- uni-app开发经验分享十一: uniapp iOS云打包修改权限提示语
打包提交appstore如果用到了如下权限需要修改提示语,详细描述使用这个权限的原因,如不修改提示语appstore审核可能会被拒绝.Apple的原则是,如果一个app想要申请用户同意某个隐私信息访问 ...
- .net code+vue 文件上传
后端技术 .net code 官方文档 https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/file-uploads?view=aspnet ...
- Python格式化处理json数据的方式
1.问题 在遇到json数据的过程中,我们经常需要获取json数据中某个值的操作,如果是用get方法去取比较繁琐,接下来介绍两种方式来取值. 2.jsonpath来格式化处理json数据 2.1介绍 ...
- Java层面上下文切换
前言 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的"同一时间点",而是 多个任务 ...
- axios用法
1 axios.get('https://api.apiopen.top/getJoke?type=all', { 2 params: {//用于传参 3 type: 'all' 4 } 5 }).t ...
- 每天学一点 Vue3(一) CND方式的安装以及简单使用
简介 感觉vue3的新特性很舒服,这样才是写软件的感觉嘛.打算用Vue实现自己的一些想法. Vue3还有几个必备库,比如Vue-Router(负责路由导航).Vuex(状态管理.组件间通信),还有第三 ...
- 四. Ribbon负载均衡服务调用
1. 概述 1.1 Ribbon是什么 SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端,是负载均衡的工具. Ribbon是Netflix发布的开源项目,主要功能 ...