一:讲故事

上一篇介绍的 6 个特性从园子里的反馈来看效果不错,那这一篇就再带来 6 个特性同大家一起欣赏。

二:特性分析

1. 像弱类型语言一样解析 json

大家都知道弱类型的语言有很多,如: nodejs,python,php,它们有一个的地方就是处理json,不需要像 强类型语言 那样还要给它配一个类,什么意思呢? 就拿下面的 json 说事。


{
"DisplayName": "新一代算法模型",
"CustomerType": 1,
"Report": {
"TotalCustomerCount": 1000,
"TotalTradeCount": 50
},
"CustomerIDHash": [1,2,3,4,5]
}

这个 json 如果想灌到 C# 中处理,你就得给它定义一个适配的类,就如 初篇 的客户算法模型类,所以这里就有了一个需求,能不能不定义类也可以自由解析上面这串 json 呢??? 哈哈,当然是可以的, 反序列化成 Dictionary 即可,就拿提取 Report.TotalCustomerCountCustomerIDHash 这两个字段演示一下。


static void Main(string[] args)
{
var json = @"{
'DisplayName': '新一代算法模型',
'CustomerType': 1,
'Report': {
'TotalCustomerCount': 1000,
'TotalTradeCount': 50
},
'CustomerIDHash': [1,2,3,4,5]
}"; var dict = JsonConvert.DeserializeObject<Dictionary<object, object>>(json); var report = dict["Report"] as JObject;
var totalCustomerCount = report["TotalCustomerCount"]; Console.WriteLine($"totalCustomerCount={totalCustomerCount}"); var arr = dict["CustomerIDHash"] as JArray;
var list = arr.Select(m => m.Value<int>()).ToList(); Console.WriteLine($"list={string.Join(",", list)}");
}

2. 如何让json中的枚举保持更易读的字符串型

这句话是什么意思呢? 默认情况下, SerializeObject 会将 Model 中的 Enum 变成数值型,大家都知道数值型语义性是非常差的,如下代码所示:


static void Main(string[] args)
{
var model = new ThreadModel() { ThreadStateEnum = System.Threading.ThreadState.Running }; var json = JsonConvert.SerializeObject(model); Console.WriteLine(json);
} class ThreadModel
{
public System.Threading.ThreadState ThreadStateEnum { get; set; }
}

对吧,确实语义特别差,那能不能直接生成 Running 这种字符串形式呢? 当然可以了。。。改造如下:


var json = JsonConvert.SerializeObject(model, new StringEnumConverter());

这里可能就有人钻牛角尖了,能不能部分指定让枚举生成 string,其他的生成 int ,没关系,这也难不倒我,哪里使用就用 JsonConverter 标记哪里。。。


static void Main(string[] args)
{
var model = new ThreadModel()
{
ThreadStateEnum = System.Threading.ThreadState.Running,
TaskStatusEnum = TaskStatus.RanToCompletion
}; var json = JsonConvert.SerializeObject(model); Console.WriteLine(json);
} class ThreadModel
{
public System.Threading.ThreadState ThreadStateEnum { get; set; } [JsonConverter(typeof(StringEnumConverter))]
public TaskStatus TaskStatusEnum { get; set; }
}

3. 格式化 json 中的时间类型

在 model 转化成 json 的过程中,总少不了 时间类型,为了让时间类型 可读性更高,通常会 格式化为 YYYY年/MM月/dd日 ,那如何实现呢? 很简单撒,在 JsonConvert 中也是一个 枚举 帮你搞定。。。


static void Main(string[] args)
{
var json = JsonConvert.SerializeObject(new Order()
{
OrderTitle = "女装大佬",
Created = DateTime.Now
}, new JsonSerializerSettings
{
DateFormatString = "yyyy年/MM月/dd日",
}); Console.WriteLine(json);
}
public class Order
{
public string OrderTitle { get; set; }
public DateTime Created { get; set; }
}

对了,我记得很早的时候,C# 自带了一个 JavaScriptSerializer, 也是用来进行 model 转 json的,但是它会将 datetime 转成 时间戳,而不是时间字符串形式,如果你因为特殊原因想通过 JsonConvert 将时间生成时间戳的话,也是可以的, 用 DateFormatHandling.MicrosoftDateFormat 枚举指定一下即可,如下:

4. 对一些常用设置进行全局化

在之前所有演示的特性技巧中都是在 JsonConvert 上指定的,也就是说 100 个 JsonConvert 我就要指定 100 次,那有没有类似一次指定,整个进程通用呢? 这么强大的 Newtonsoft 早就支持啦, 就拿上面的 Order 举例:


JsonConvert.DefaultSettings = () =>
{
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented
};
return settings;
}; var order = new Order() { OrderTitle = "女装大佬", Created = DateTime.Now }; var json1 = JsonConvert.SerializeObject(order);
var json2 = JsonConvert.SerializeObject(order); Console.WriteLine(json1);
Console.WriteLine(json2);

可以看到,Formatting.Indented 对两串 json 都生效了。

5. 如何保证 json 到 model 的严谨性 及提取 json 未知字段

有时候我们有这样的需求,一旦 json 中出现 model 未知的字段,有两种选择: 要么报错,要么提取出未知字段,在 Newtonsoft 中默认的情况是忽略,场景大家可以自己找哈。

  • 未知字段报错

static void Main(string[] args)
{
var json = "{'OrderTitle':'女装大佬', 'Created':'2020/6/23','Memo':'订单备注'}"; var order = JsonConvert.DeserializeObject<Order>(json, new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error
}); Console.WriteLine(order);
} public class Order
{
public string OrderTitle { get; set; }
public DateTime Created { get; set; }
public override string ToString()
{
return $"OrderTitle={OrderTitle}, Created={Created}";
}
}

  • 提取未知字段

我依稀的记得 WCF 在这种场景下也是使用一个 ExtenstionDataObject 来存储客户端传过来的未知字段,有可能是客户端的 model 已更新,server端还是旧版本,通常在 json 序列化中也会遇到这种情况,在 JsonConvert 中使用 _additionalData 就可以帮你搞定,在 OnDeserialized 这种AOP方法中进行拦截,如下代码:


static void Main(string[] args)
{
var json = "{'OrderTitle':'女装大佬', 'Created':'2020/6/23','Memo':'订单备注'}"; var order = JsonConvert.DeserializeObject<Order>(json); Console.WriteLine(order);
} public class Order
{
public string OrderTitle { get; set; } public DateTime Created { get; set; } [JsonExtensionData]
private IDictionary<string, JToken> _additionalData; public Order()
{
_additionalData = new Dictionary<string, JToken>();
} [OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
var dict = _additionalData;
} public override string ToString()
{
return $"OrderTitle={OrderTitle}, Created={Created}";
}
}

6. 开启 JsonConvert 详细日志功能

有时候在查阅源码的时候开启日志功能更加有利于理解源码的内部运作,所以这也是一个非常实用的功能,看看如何配置吧。


static void Main(string[] args)
{
var json = "{'OrderTitle':'女装大佬', 'Created':'2020/6/23','Memo':'订单备注'}"; MemoryTraceWriter traceWriter = new MemoryTraceWriter(); var account = JsonConvert.DeserializeObject<Order>(json, new JsonSerializerSettings
{
TraceWriter = traceWriter
}); Console.WriteLine(traceWriter.ToString());
} public class Order
{
public string OrderTitle { get; set; } public DateTime Created { get; set; } public override string ToString()
{
return $"OrderTitle={OrderTitle}, Created={Created}";
}
}

三:总结

嘿嘿,这篇 6 个特性就算说完了, 结合上一篇一共 12 个特性,是不是非常简单且实用,后面准备给大家带来一些源码解读吧! 希望本篇对您有帮助,谢谢!

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

Newtonsoft 六个超简单又实用的特性,值得一试 【下篇】的更多相关文章

  1. Newtonsoft 六个超简单又实用的特性,值得一试 【上篇】

    一:讲故事 看完官方文档,阅读了一些 Newtonsoft 源码,对它有了新的认识,先总结 六个超经典又实用的特性,同大家一起分享,废话不多说,快来一起看看吧~~~ 二:特性分析 1. 代码格式化 如 ...

  2. ASP.NET中一种超简单的Ajax解决方案

    为什么是Ajax2? 因为之前有一个blqw.Ajax,并且已经在项目中投入使用了,但是没有这个方便,这个是后来才弄的,为了纪念第一版的blqw.Ajax,所以这个就2了... 话说看了评论才发现,原 ...

  3. 超简单的全新win10安装

    1.准备工作! 这里说一下需要装系统的东西: 至少8G的U盘或内存卡 一台Windows电脑 在要安装的电脑上至少有16G的空间,最好至少64G. 2.现成电脑下载文件(已经有重装系统U盘跳过这一步) ...

  4. 分享六个基于Bootstrap的实用开发教程和模板演示

    关于Bootstrap,相信大家一定不陌生,它已经成为现在主流产业的一个重要工具,Bootstrap提供了优雅的HTML和CSS规范,它基于jQuery框架开发的,它在jQuery框架的基础上进行了更 ...

  5. 【Android自己定义View实战】之自己定义超简单SearchView搜索框

    [Android自己定义View实战]之自己定义超简单SearchView搜索框 这篇文章是对之前文章的翻新,至于为什么我要又一次改动这篇文章?原因例如以下 1.有人举报我抄袭,原文链接:http:/ ...

  6. 【转载】手把手教你使用Git(简单,实用)

    手把手教你使用Git(简单,实用) 标签: git 2016年04月21日 20:51:45 1328人阅读 评论(0) 收藏 举报 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. ...

  7. 超简单集成 HMS ML Kit 实现最大脸微笑抓拍

    前言 如果大家对 HMS ML Kit 人脸检测功能有所了解,相信已经动手调用我们提供的接口编写自己的 APP 啦.目前就有小伙伴在调用接口的过程中反馈,不太清楚 HMS ML Kit 文档中的 ML ...

  8. 把C#程序(含多个Dll)合并成一个Exe的超简单方法

    开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. 但是,很多时候我们本想开发一款只需要一个exe就能完美运行的小工具.那该怎么办呢? 下文介绍一种超 ...

  9. 记住密码超简单实现(C#)

    实现效果如下 实现过程 [Serializable] class User { //记住密码 private string loginID; public string LoginID { get { ...

随机推荐

  1. linux:基本指令

    指令标准格式 指令主体 [选项][操作对象] 基础指令 ls 1.ls 列出当前工作目录下的所有文件/文件夹的名称 2.ls  路径 列出指定路径下的所有文件/文件夹的名称 路径: 1.相对路径 会用 ...

  2. Java实现 LeetCode 785 判断二分图(分析题)

    785. 判断二分图 给定一个无向图graph,当这个图为二分图时返回true. 如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我 ...

  3. Java实现蓝桥杯 算法提高 线段和点

    算法提高 线段和点 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 有n个点和m个区间,点和区间的端点全部是整数,对于点a和区间[b,c],若a>=b且a<=c,称点a满 ...

  4. Java实现 蓝桥杯 算法训练 相邻数对(暴力)

    试题 算法训练 相邻数对 问题描述 给定n个不同的整数,问这些数中有多少对整数,它们的值正好相差1. 输入格式 输入的第一行包含一个整数n,表示给定整数的个数. 第二行包含所给定的n个整数. 输出格式 ...

  5. Java实现 LeetCode 713 乘积小于K的子数组(子集数量+双指针)

    713. 乘积小于K的子数组 给定一个正整数数组 nums. 找出该数组内乘积小于 k 的连续的子数组的个数. 示例 1: 输入: nums = [10,5,2,6], k = 100 输出: 8 解 ...

  6. Java实现 蓝桥杯 算法训练 删除数组零元素

    算法训练 删除数组零元素 时间限制:1.0s 内存限制:512.0MB 提交此题 从键盘读入n个整数放入数组中,编写函数CompactIntegers,删除数组中所有值为0的元素,其后元素向数组首端移 ...

  7. Java实现 蓝桥杯VIP 算法提高 不同单词个数统计

    算法提高 不同单词个数统计 时间限制:1.0s 内存限制:512.0MB 问题描述 编写一个程序,输入一个句子,然后统计出这个句子当中不同的单词个数.例如:对于句子"one little t ...

  8. java实现串的反转

    串的反转 反转串 我们把"cba"称为"abc"的反转串. 求一个串的反转串的方法很多.下面就是其中的一种方法,代码十分简洁(甚至有些神秘),请聪明的你通过给出 ...

  9. java实现第四届蓝桥杯大臣的旅费

    大臣的旅费 题目描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大 ...

  10. C++拷贝构造函数被调用的时机

    拷贝构造函数调用的几种情况: 当用类的一个对象去初始化该类的另一个对象(或引用)时系统自动调用拷贝构造函数实现拷贝赋值. 若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数.( ...