c# Newtonsoft 六个值得使用的特性(下)

作者:一线码农 时间:2022-02-18 11:38:32 

一:讲故事

上一篇介绍的 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.TotalCustomerCount CustomerIDHash 这两个字段演示一下。


 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)}");
 }

c# Newtonsoft 六个值得使用的特性(下)

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; }
}

c# Newtonsoft 六个值得使用的特性(下)

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


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

c# Newtonsoft 六个值得使用的特性(下)

这里可能就有人钻牛角尖了,能不能部分指定让枚举生成 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; }
 }

c# Newtonsoft 六个值得使用的特性(下)

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# Newtonsoft 六个值得使用的特性(下)

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

c# Newtonsoft 六个值得使用的特性(下)

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);

c# Newtonsoft 六个值得使用的特性(下)

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}";   }  }  

c# Newtonsoft 六个值得使用的特性(下)

  • 提取未知字段

我依稀的记得 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}";
 }
}

c# Newtonsoft 六个值得使用的特性(下)

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}";
  }
 }

c# Newtonsoft 六个值得使用的特性(下)

三:总结

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

来源:https://www.cnblogs.com/huangxincheng/p/13180113.html

标签:c#,Newtonsoft,特性
0
投稿

猜你喜欢

  • SpringBoot使用FreeMarker模板发送邮件

    2021-07-27 07:32:26
  • Java代码实现循环队列的示例代码

    2023-11-23 23:51:25
  • Jackson中json格式的字符串与对象的互相转换方式

    2022-01-29 03:31:07
  • 解决运行jar包出错:ClassNotFoundException问题

    2021-09-09 04:58:41
  • C# PDF Page操作设置页面切换按钮的方法

    2021-11-18 04:33:43
  • 如何在IDE部署springboot项目(有swagger和无swagger都是一样的)到服务器或者虚拟机上的docker

    2023-09-01 00:33:25
  • SpringBoot集成ElasticSearch的示例代码

    2023-05-02 05:50:28
  • Java C++题解leetcode904水果成篮

    2023-12-08 21:06:09
  • Java多线程的其他知识_动力节点Java学院整理

    2023-09-06 06:01:58
  • Swing常用组件之多行文本区JTextArea

    2023-11-08 14:16:49
  • 提升java开发效率工具lombok使用争议

    2022-06-22 03:08:18
  • C#对Word文档的创建、插入表格、设置样式等操作实例

    2021-10-24 23:13:46
  • Spring中注解方式的异步请求

    2023-11-30 18:53:54
  • 简单了解Java编程中线程的创建与守护线程

    2023-11-25 06:59:52
  • java实现简单年龄计算器

    2022-01-28 02:23:34
  • 浅谈Java中几种常见的比较器的实现方法

    2022-04-08 19:04:36
  • IDEA简单实现登录注册页面

    2023-08-06 19:10:37
  • java实现图书馆管理系统

    2023-12-10 15:50:29
  • SpringBoot自定义maven-plugin插件整合asm代码插桩

    2021-05-24 02:15:49
  • Mybatis步骤分解实现一个增删改查程序

    2021-09-16 01:12:43
  • asp之家 软件编程 m.aspxhome.com