一:背景

1. 讲故事

在开始本文之前,真的好想做个问卷调查,到底有多少人和我一样,对 JsonConvert 的认识只局限在 SerializeObjectDeserializeObject 这两个方法上(┬_┬), 这样我也好结伴同行,不再孤单落魄,或许是这两个方法基本上能够解决工作中 80% 的场景,对于我来说确实是这样,但随着编码的延续,终究还是会遇到那剩下的 20% ,所以呀。。。

我的场景是这样的:前段时间写业务代码的时候,我有一个自定义的客户算法类型的Model,这个Model中有这种算法类型下的客户群以及Report统计信息,还用了 HashSet 记录了该类型下的 CustomerID集合,为了方便讲述,我把Model简化如下:


class CustomerAlgorithmModel
{
public string DisplayName { get; set; } public int CustomerType { get; set; } public ReprotModel Report { get; set; } public HashSet<int> CustomerIDHash { get; set; }
} class ReprotModel
{
public int TotalCustomerCount { get; set; } public int TotalTradeCount { get; set; }
}

那有意思的就来了,我个人是有记日志的癖好,就想着以后不会出现死无对证的情况,然后就理所当然的使用 JsonConvert.SerializeObject, 这一下就出问题了,日志送入到了 ElasticSearch ,然后通过 Kibana 查不出来,为啥呢? 看完上面的 Model 我想你也猜到了原因,json体太大了哈,好歹 CustomerIDHash 中也有几十万个撒,这一下全导出成json了,这 size 还能小吗? 要不我写段代码看一看。


static void Main(string[] args)
{
var algorithModel = new CustomerAlgorithmModel()
{
CustomerType = 1,
DisplayName = "",
Report = new ReprotModel()
{
TotalCustomerCount = 1000,
TotalTradeCount = 50
},
CustomerIDHash = new HashSet<int>(Enumerable.Range(1, 500000))
}; var json = JsonConvert.SerializeObject(algorithModel); File.WriteAllText("1.txt", json, Encoding.UTF8); Console.WriteLine("写入完成!");
}

可以看到,仅一个json就 3.3M,这样的记录多来几打后,在 kibana 上一检索,浏览器就卡的要死,其实 CustomerIDHash 这个字段对我来说是可有可无的,就算存下来了也没啥大用,所以需求就来了,如何屏蔽掉 CustomerIDHash

二:寻求解决方案

1. 使用 JsonIgnore

有问题就网上搜啊,这一搜马上就有人告诉你可以使用 JsonIgnoreAttribute 忽略特性,加好这个特性后继续跑一下程序。


[Newtonsoft.Json.JsonIgnore]
public HashSet<int> CustomerIDHash { get; set; }

太好了,终于搞定了,但是静下心来想一想,总感觉心里有那么一点不舒服,为什么这么说,一旦你给这个 CustomerIDHash 套上了 JsonIgnore ,这就意味着它在 JsonConvet 的世界中从此消失,也不管是谁在使用这个Model, 但这并不是我的初衷,我的初衷仅仅是为了在记录日志的时候踢掉 CustomerIDHash,可千万不要影响在其他场景下的使用哈,现在这种做法就会给自己,给别人挖坑,埋下了不可预知的bug,我想你应该明白我的意思,还得继续寻找下一个方案。

2. 使用自定义的 JsonConverter

真的,Newtonsoft 太强大了,我都想写一个专题好好弥补弥补我的知识盲区,其实在这个场景中不就是想把 HashSet<int> 给屏蔽掉嘛,Newtonsoft 中专门提供了一个针对特定类型的自定义处理类,接下来我就写一段:


/// <summary>
/// 自定义一个 针对 HashSet<int> 的转换类
/// </summary>
public class HashSetConverter : Newtonsoft.Json.JsonConverter<HashSet<int>>
{
public override HashSet<int> ReadJson(JsonReader reader, Type objectType, HashSet<int> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return existingValue;
} public override void WriteJson(JsonWriter writer, HashSet<int> value, JsonSerializer serializer)
{
writer.WriteNull();
}
}

就是这么简单,然后就可以在 SerializeObject 的时候指定下自定义的 HashSetConverter 即可,然后再将程序跑起来看一下。


var json = JsonConvert.SerializeObject(algorithModel, Formatting.Indented, new HashSetConverter());

从图中看,貌似也是解决了,但我突然发现自己要钻牛角尖了,如果我的实体中又来了一个顶级优质客户群的 TopNCustomerIDHash,但因为这个CustomerID 比较少,我希望在 Json 中能保留下来,然后就是踢掉的那个 CustomerIDHash 我要保留 CustomerIDHash.Length ,哈哈,搞事情哈,那接下来怎么解决呢?

  • 修改 Model 实体

class CustomerAlgorithmModel
{
public HashSet<int> CustomerIDHash { get; set; } // topN 优质客户群
public HashSet<int> TopNCustomerIDHash { get; set; }
}
  • HashSetConverter 增加逻辑鉴别是否为保留字段

public override void WriteJson(JsonWriter writer, HashSet<int> value, JsonSerializer serializer)
{
if (writer.Path == "TopNCustomerIDHash")
{
writer.WriteStartArray(); foreach (var item in value)
{
writer.WriteValue(item);
} writer.WriteEndArray();
}
else
{
writer.WriteValue(value.Count);
}
}
  • 最后给 TopNCustomerIDHash 赋值

var algorithModel = new CustomerAlgorithmModel()
{
CustomerType = 1,
DisplayName = "",
Report = new ReprotModel()
{
TotalCustomerCount = 1000,
TotalTradeCount = 50
},
CustomerIDHash = new HashSet<int>(Enumerable.Range(1, 500000)),
TopNCustomerIDHash = new HashSet<int>(Enumerable.Range(1, 10)),
};

三块都搞定后就可以把程序跑起来了,如下图:

貌似钻牛角尖的问题是解决了,既然钻牛角尖肯定要各种鄙视,比如这里的 ReportModel 我是不需要的,CustomerType 我也是不需要的,我仅仅需要看一下 DisplayNameTotalCustomerCount 这两个字段就可以了, 那这个要怎么解决呢?

3. 使用 匿名类型

确实很多时候记日志,就是为了跟踪 Model 中你特别关心的那几个字段,所以掺杂了多余的字段确实也是没必要的,这里可以用匿名来解决,我就来写一段代码:


var json = JsonConvert.SerializeObject(new
{
algorithModel.DisplayName,
algorithModel.Report.TotalCustomerCount
}, Formatting.Indented);

三: 总结

虽然阻击了几个回合,但同时也发现了 Newtonsoft 中还有特别多的未挖掘功能,真的需要好好研究研究,源码已下好,接下来准备做个系列来解剖一下,值得一提的是 .Net中已自带了 System.Text.Json.JsonSerializer 类,目前来看功能还不算太丰富,简单用用还是可以的,本篇就说到这里,希望对您有帮助。


如您有更多问题与我互动,扫描下方进来吧~

对 JsonConvert 的认识太肤浅了,终于还是遇到了问题的更多相关文章

  1. Shader的学习方法总结

    最近网友candycat1992的新书<Unity Shader入门精要>出版了,估计万千的中国unity开发者又要掀起一波学Shader热潮了.我也想把自己这几年学习Shader的一些历 ...

  2. [转]MySQL去除查询结果重复值

    在使用MySQL时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所 ...

  3. 用distinct在MySQL中查询多条不重复记录值[转]

    在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所 ...

  4. mysql中函数DISTINCT,group by,CONCAT及GROUP_CONCAT的使用

    一:DISTINCT 在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是 ...

  5. cfa,cpa,

    CFA考试内容分为三个不同级别,分别是方式是Level I.Level II和Level III. 考试在全球各个地点统一举行,每个考生必须依次完成三个不同级别的考试.CFA资格考试采用全英文,候选人 ...

  6. 探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 构建记事本应用

    前言 首先说明这并不是一个教程贴,而记事本应用是网上早有的案例,对于学习 vuex 非常有帮助.我的目的是探索 vuex 2.0 ,然后使用 vue 2.0 + vuex 2.0 重写这个应用,其中最 ...

  7. 自己动手实现XXX系列

    前记: 最近看了rongjun的一片文章:自己动手实现jdk代理类.按照上面的例子敲完才发现,JDK动态代理 实现底层原来如此简单,只是大量的使用了反射,类编译,类加载一些常规的东西 而且本质也是如实 ...

  8. 探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 构建记事本应用23

    前言 首先说明这并不是一个教程贴,而记事本应用是网上早有的案例,对于学习 vuex 非常有帮助.我的目的是探索 vuex 2.0 ,然后使用 vuejs 2.0 + vuex 2.0 重写这个应用,其 ...

  9. 关于Python json解析过程遇到的TypeError: expected string or buffer

    关于Python json解析过程遇到的问题:(爬取天气json数据所遇到的问题http://tianqi.2345.com/) part.1 url——http://tianqi.2345.com/ ...

随机推荐

  1. Kubernetes Ingress简单入门

    作者:Nick Ramirez 原文链接:https://thenewstack.io/kubernetes-ingress-for-beginners/ 本文转载自Rancher Labs 不知道你 ...

  2. GRpc添加客户端的四种方式

    随着微服务的发展,相信越来越多的.net人员也开始接触GRpc这门技术,大家生成GRpc客户端的方式也各不相同,今天给大家介绍一下依据Proto文件生成Rpc客户端的四种方式 前提:需要安装4个Nug ...

  3. vue使用IntersectionObserver实现无限下拉信息流

    基于 IntersectionObserver 异步监听方法,实现无线信息流下拉加载, https://developer.mozilla.org/zh-CN/docs/Web/API/Interse ...

  4. Mysql索引的基本知识和用处

    2020-05-29 15:38:27 一.索引的优点 1.能大大减少服务器需要扫描的数据量. 2.帮助服务器避免排序和临时表. 3.将随机io变成顺序io. 二.索引的用处 能够快速匹配where条 ...

  5. 在线编写复杂的数学公式--EdrawMath

    网址: EdrawMath , 非常好用

  6. 这个Maven依赖的问题,你敢说你没遇到过

    Maven 依赖没处理好的话经常会导致发生一些问题,非常烦.今天给大家分享一个依赖相关的问题,说不定你之前就遇到过. 问题背景 有个 ES 搜索的项目,刚开始还是好好的状态,过了一段时间,然后就发现启 ...

  7. python调用大漠插件教程01注册大漠

    使用大漠有两种方法,一种是直接调用特殊的dll实现不注册就能使(本人不会),另一种则是注册后使用. 如何用python注册大漠? from win32com.client import Dispatc ...

  8. Java实现 蓝桥杯VIP 算法训练 入学考试

    问题描述 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:" ...

  9. Java实现 蓝桥杯VIP 算法提高 统计单词数

    算法提高 统计单词数 时间限制:1.0s 内存限制:512.0MB 问题描述 统计输入英文文章段落中不同单词(单词有大小写之分, 但统计时忽略大小写)各自出现的次数. 输入段落中所含单词的总数不超过1 ...

  10. 第三届蓝桥杯C++B组国(决)赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.星期几 1949年的国庆节(10月1日)是星期六. 今年(2012)的国庆节是星期一. 那么,从建国到现在,有几次国庆节正好是星期日呢 ...