c# Newtonsoft 六個(gè)值得使用的特性(下)
一:講故事
上一篇介紹的 6 個(gè)特性從園子里的反饋來看效果不錯(cuò),那這一篇就再帶來 6 個(gè)特性同大家一起欣賞。
二:特性分析
1. 像弱類型語言一樣解析 json
大家都知道弱類型的語言有很多,如: nodejs,python,php,它們有一個(gè)🐮👃的地方就是處理json,不需要像 強(qiáng)類型語言 那樣還要給它配一個(gè)類,什么意思呢? 就拿下面的 json 說事。
{
"DisplayName": "新一代算法模型",
"CustomerType": 1,
"Report": {
"TotalCustomerCount": 1000,
"TotalTradeCount": 50
},
"CustomerIDHash": [1,2,3,4,5]
}
這個(gè) json 如果想灌到 C# 中處理,你就得給它定義一個(gè)適配的類,就如 初篇 的客戶算法模型類,所以這里就有了一個(gè)需求,能不能不定義類也可以自由解析上面這串 json 呢??? 哈哈,當(dāng)然是可以的, 反序列化成 Dictionary 即可,就拿提取 Report.TotalCustomerCount 和 CustomerIDHash 這兩個(gè)字段演示一下。
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中的枚舉保持更易讀的字符串型
這句話是什么意思呢? 默認(rèn)情況下, SerializeObject 會(huì)將 Model 中的 Enum 變成數(shù)值型,大家都知道數(shù)值型語義性是非常差的,如下代碼所示:
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; }
}

對(duì)吧,確實(shí)語義特別差,那能不能直接生成 Running 這種字符串形式呢? 當(dāng)然可以了。。。改造如下:
var json = JsonConvert.SerializeObject(model, new StringEnumConverter());

這里可能就有人鉆牛角尖了,能不能部分指定讓枚舉生成 string,其他的生成 int ,沒關(guān)系,這也難不倒我,哪里使用就用 JsonConverter 標(biāo)記哪里。。。
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 中的時(shí)間類型
在 model 轉(zhuǎn)化成 json 的過程中,總少不了 時(shí)間類型,為了讓時(shí)間類型 可讀性更高,通常會(huì) 格式化為 YYYY年/MM月/dd日 ,那如何實(shí)現(xiàn)呢? 很簡(jiǎn)單撒,在 JsonConvert 中也是一個(gè) 枚舉 幫你搞定。。。
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; }
}

對(duì)了,我記得很早的時(shí)候,C# 自帶了一個(gè) JavaScriptSerializer, 也是用來進(jìn)行 model 轉(zhuǎn) json的,但是它會(huì)將 datetime 轉(zhuǎn)成 時(shí)間戳,而不是時(shí)間字符串形式,如果你因?yàn)樘厥庠蛳胪ㄟ^ JsonConvert 將時(shí)間生成時(shí)間戳的話,也是可以的, 用 DateFormatHandling.MicrosoftDateFormat 枚舉指定一下即可,如下:

4. 對(duì)一些常用設(shè)置進(jìn)行全局化
在之前所有演示的特性技巧中都是在 JsonConvert 上指定的,也就是說 100 個(gè) JsonConvert 我就要指定 100 次,那有沒有類似一次指定,整個(gè)進(jìn)程通用呢? 這么強(qiáng)大的 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);

5. 如何保證 json 到 model 的嚴(yán)謹(jǐn)性 及提取 json 未知字段
有時(shí)候我們有這樣的需求,一旦 json 中出現(xiàn) model 未知的字段,有兩種選擇: 要么報(bào)錯(cuò),要么提取出未知字段,在 Newtonsoft 中默認(rèn)的情況是忽略,場(chǎng)景大家可以自己找哈。
- 未知字段報(bào)錯(cuò)
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 在這種場(chǎng)景下也是使用一個(gè) ExtenstionDataObject 來存儲(chǔ)客戶端傳過來的未知字段,有可能是客戶端的 model 已更新,server端還是舊版本,通常在 json 序列化中也會(huì)遇到這種情況,在 JsonConvert 中使用 _additionalData 就可以幫你搞定,在 OnDeserialized 這種AOP方法中進(jìn)行攔截,如下代碼:
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 詳細(xì)日志功能
有時(shí)候在查閱源碼的時(shí)候開啟日志功能更加有利于理解源碼的內(nèi)部運(yùn)作,所以這也是一個(gè)非常實(shí)用的功能,看看如何配置吧。
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}";
}
}

三:總結(jié)
嘿嘿,這篇 6 個(gè)特性就算說完了, 結(jié)合上一篇一共 12 個(gè)特性,是不是非常簡(jiǎn)單且實(shí)用,后面準(zhǔn)備給大家?guī)硪恍┰创a解讀吧! 希望本篇對(duì)您有幫助,謝謝!
以上就是c# Newtonsoft 六個(gè)值得使用的特性(下)的詳細(xì)內(nèi)容,更多關(guān)于c# Newtonsoft 特性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用C#創(chuàng)建Windows服務(wù)的實(shí)例代碼
這篇文章主要介紹了使用C#創(chuàng)建Windows服務(wù)的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07
C#實(shí)現(xiàn)的簡(jiǎn)單驗(yàn)證碼識(shí)別實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)的簡(jiǎn)單驗(yàn)證碼識(shí)別實(shí)例,只適應(yīng)一些簡(jiǎn)單的驗(yàn)證碼,需要的朋友可以參考下2014-06-06
C#實(shí)現(xiàn)讀取二維數(shù)組集合并輸出到Word預(yù)設(shè)表格
這篇文章主要為大家詳細(xì)介紹了如何使用C#實(shí)現(xiàn)讀取二維數(shù)組集合并輸出到Word預(yù)設(shè)表格,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
C#中的multipart/form-data提交文件和參數(shù)
這篇文章主要介紹了C#中的multipart/form-data提交文件和參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
C#實(shí)現(xiàn)XML與實(shí)體類之間相互轉(zhuǎn)換的方法(序列化與反序列化)
這篇文章主要介紹了C#實(shí)現(xiàn)XML與實(shí)體類之間相互轉(zhuǎn)換的方法,涉及C#序列化與反序列化操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06

