日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

c# json datatable_KoobooJson一款高性能且轻量的JSON库

發(fā)布時(shí)間:2024/8/1 C# 76 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c# json datatable_KoobooJson一款高性能且轻量的JSON库 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

(給DotNet加星標(biāo),提升.Net技能)

轉(zhuǎn)自:小曾看世界

cnblogs.com/1996V/p/10607916.html

KoobooJson - 更小更快的C# JSON序列化工具(基于表達(dá)式樹(shù)構(gòu)建)

C#領(lǐng)域有很多成熟的開(kāi)源JSON框架,最著名且使用最多的是 Newtonsoft.Json ,然而因?yàn)榘姹镜?其代碼要兼容從.NET 2.0到現(xiàn)在的最新的.NET框架,并且要支持.NET平臺(tái)下的其它語(yǔ)言,所以最新發(fā)布版本的Newtonsoft.Json其dll大小接近700k,另一方面,因?yàn)槠鋸?fù)雜的迭代歷史導(dǎo)致它的代碼為了維護(hù)向下擴(kuò)展性和向上兼容性而舍棄一些性能。

如果你不太在乎體積和性能的話,那么 Newtonsoft.Json 無(wú)疑是一款很好的選擇。但是如果你在意性能的話,在github上仍然有一些出名的以速度為稱(chēng)的C# JSON框架,其中最為人知的應(yīng)該是 JIL , JIL有著出色的性能是因?yàn)樗捎昧舜罅康募铀偌夹g(shù),但這也帶來(lái)了一些局限性,它不夠靈活,對(duì)object類(lèi)型的解析必須得調(diào)用它的另一個(gè)API,并且因?yàn)槌鲇谛阅芸紤]其采用的是Emit技術(shù),不易維護(hù),在我的測(cè)試中有很多類(lèi)型它不支持。

但是JIL的地位是顯而易見(jiàn)的,因?yàn)樗某霈F(xiàn),github上有著很多相仿思路的以速度為稱(chēng)的JSON框架,幾乎每個(gè)都稱(chēng)自己是最快的,但實(shí)際上很少有超越JIL的,并且它們中的大部分沒(méi)有一個(gè)良好的文檔,這導(dǎo)致我在做性能測(cè)試時(shí),我想改個(gè)配置都得對(duì)源碼全局搜索花費(fèi)一定時(shí)間。

在說(shuō)回程序集大小,JIL的最新發(fā)布版本是500k,并且其依賴一個(gè)庫(kù),加起來(lái)是800k大小。

那么,我講這些,大家應(yīng)該知道我想要表達(dá)什么!

是的考慮到前面種種,這些都不是在某種場(chǎng)景最理想化的那種JSON庫(kù),所以我寫(xiě)了一款以體積更小,速度更快,類(lèi)型覆蓋更廣的開(kāi)源C# JSON框架KoobooJson。

在我正式介紹KoobooJson之前,我要介紹一下什么是Kooboo!

Kooboo是我們老板用C#編寫(xiě)的一個(gè)開(kāi)源的非常神奇的網(wǎng)站開(kāi)發(fā)工具,它是一個(gè)類(lèi)CMS生成器,但其從數(shù)據(jù)庫(kù),前端引擎,到各種網(wǎng)絡(luò)協(xié)議服務(wù)器都是用c#自主創(chuàng)造的,幾乎很少使用到第三方庫(kù),它編譯后的發(fā)布版本僅有幾M,而正是因?yàn)閮H僅只有幾M,為了Json框架不要太影響主程序的大小,這才有了KoobooJson此次的誕生!

Kooboo是開(kāi)源的:https://github.com/Kooboo/Kooboo

KoobooJson自然也是開(kāi)源的:https://github.com/Kooboo/Json

在NuGet包中可以直接搜索 KoobooJson 下載使用即可

什么是KoobooJson?

KoobooJson是一款C#的JSON工具,其主要通過(guò)表達(dá)式技術(shù)構(gòu)建,最低支持.NET 4.5(可以支持.NET 4.0,但考慮到一些因素,最終沒(méi)有支持,有需要支持的可以自行源碼分支更改。

另外,幾乎每個(gè)以性能號(hào)稱(chēng)的JSON框架都最低支持.NET 4.5),最低支持.NET Core 2.0,提交小巧,性能出色,類(lèi)型覆蓋廣是KoobooJson的優(yōu)點(diǎn)!

KoobooJson的優(yōu)點(diǎn)

1、小巧

目前KoobooJson只有130k, 并且沒(méi)有任何額外依賴項(xiàng), KoobooJson當(dāng)前支持框架版本.NET 4.5 .NET Core 2+ .NET Standard 2

2、快速

KoobooJson 遵循JSON RFC8259規(guī)范, 是一款適用于C#的快速的Json文本序列化器

它基于表達(dá)式樹(shù)構(gòu)建, 在運(yùn)行時(shí)會(huì)動(dòng)態(tài)的為每個(gè)類(lèi)型生成高效的解析代碼, 這過(guò)程包括: 利用靜態(tài)泛型模板進(jìn)行緩存, 避免字典查詢開(kāi)銷(xiāo), 避免裝箱拆箱消耗, 緩沖池復(fù)用, 加速字節(jié)復(fù)制...

KoobooJson生成代碼的方式并沒(méi)有采用Emit, 而是采用ExpressionTree. ExpressionTree相比Emit而言, 它不能像Emit直接寫(xiě)出最優(yōu)的IL代碼, 它依賴于下層的編譯器, 在某些時(shí)候它會(huì)多生成一些不必要的IL代碼路徑, 故而性能上有所遜色. 但相較于幾乎沒(méi)有類(lèi)型檢查的Emit而言, ExpressionTree不會(huì)出現(xiàn)各種莫名其妙的錯(cuò)誤, 它更加安全, 也更加容易擴(kuò)展維護(hù).

雖然ExpressionTree與Emit相比在性能方面可能會(huì)有所差異, 但是KoobooJson的表現(xiàn)卻相當(dāng)亮眼!

上圖是使用BenchmarkDotNet在.NET Core 2.1上做的Json序列化和反序列化的性能測(cè)試,隨機(jī)生成大量的測(cè)試數(shù)據(jù),迭代100次后產(chǎn)生的結(jié)果,基準(zhǔn)報(bào)告(https://github.com/Kooboo/Json/tree/master/Kooboo.Json.Benchmark/Reports)

BenchmarkDotNet=v0.10.0.8550U CPU 8 logical and 2.1.64bit RyuJIT Job-XEQPPS : 2.1.64bit RyuJIT

3、覆蓋類(lèi)型廣

在類(lèi)型定義上, KoobooJson并沒(méi)有單獨(dú)實(shí)現(xiàn)每個(gè)集合或鍵值對(duì)類(lèi)型, 而是對(duì)這些FCL類(lèi)型進(jìn)行劃分成不同的模板

a. KoobooJson將序列化分為5種類(lèi)型:

  • 原始類(lèi)型?

它包括 Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single.

  • 所有擁有鍵值對(duì)行為的類(lèi)型

任何能夠?qū)崿F(xiàn)IDictionary<>或能夠?qū)崿F(xiàn)IDictionary且能夠通過(guò)構(gòu)造函數(shù)注入鍵值對(duì)的類(lèi)型, 都將以鍵值對(duì)方式進(jìn)行解析

  • 所有擁有集合行為的類(lèi)型?

任何能夠?qū)崿F(xiàn)IEnumable并且滿足IColloction的Add行為或擁有自己獨(dú)特的集合行為且能夠通過(guò)構(gòu)造函數(shù)注入集合的類(lèi)型, 都將以集合方式進(jìn)行解析

  • 特殊類(lèi)型?

如Nullable<>, Lazy<>, Guid, Datatable, DateTime, Type, Task, Thread, Timespan...等等這些特定的類(lèi)型實(shí)現(xiàn)

  • 常規(guī)Model的鍵值對(duì)類(lèi)型?

在KoobooJson中, 如果當(dāng)類(lèi)型不滿足上述4種時(shí), 將會(huì)以鍵值對(duì)的形式來(lái)對(duì)其解析, KoobooJson會(huì)對(duì)Model中公開(kāi)的所有元素進(jìn)行序列化, 在這個(gè)環(huán)節(jié), 幾乎配置器中所有的配置都是有關(guān)Model的. 諸如別名, 忽略特性, 指定構(gòu)造函數(shù), 忽略堆棧循環(huán)引用, 首字母大小寫(xiě), 格式化器... 值得一提的是, 在對(duì)接口類(lèi)型進(jìn)行反序列化時(shí), KoobooJson默認(rèn)會(huì)自動(dòng)創(chuàng)建并返回一個(gè)實(shí)現(xiàn)于該接口的對(duì)象.

b. 在對(duì)類(lèi)型的解析上, 其中浮點(diǎn)型,日期時(shí)間類(lèi)型, GUID的解析是參照了JIL的代碼, 在此表示感謝.

作為一款活躍的Json庫(kù), KoobooJson會(huì)不斷支持更多的類(lèi)型, 這其中, 因?yàn)閷?duì)FCL中的鍵值對(duì)和集合的行為進(jìn)行歸納, 所以對(duì)于這兩種類(lèi)型, KoobooJson并不像其它框架一樣去特定的為每種類(lèi)型單獨(dú)實(shí)現(xiàn), 實(shí)際上, 第2和3所定義的規(guī)則可以容納FCL中的大多數(shù)鍵值對(duì)或集合類(lèi)型.

目前KoobooJson所覆蓋的類(lèi)型包括 : Hashtable, SortedList, ArrayList, IDictionary, Dictionary, IList,List<>, IEnumerable<>, IEnumerable, ICollection, ICollection<>, Stack<>, Queue<>, ConcurrentBag<>, ConcurrentQueue<>, ConcurrentStack<>, SortedDictionary, ConcurrentDictionary, SortedList, IReadOnlyDictionary, ReadOnlyDictionary, ObservableCollection<>, HashSet<>, SortedSet<>, LinkedList<>, ReadOnlyCollection<>, ArraySegment<>, Stack, Queue, IReadOnlyList<>, IReadOnlyCollection<>, ReadOnlyCollection<>, ISet<>, BitArray, URI, NameValueCollection, StringDictionary, ExpandoObject, StringBuilder, Nullable<>, Lazy<>, Guid, Datatable, DateTime, Type, Task, Thread, Timespan, Enum, Exception, Array[], Array[,,,,,]...

KoobooJson的實(shí)現(xiàn)

序列化

class UserModel
{
public object Obj;
public string Name;
public int Age;
}
string json = JsonSerializer.ToJson(new UserModel());

在對(duì)類(lèi)型第一次序列化時(shí), KoobooJson會(huì)為這個(gè)類(lèi)型生成大致是這樣的解析代碼.

void WriteUserModel(UserModel model,JsonSerializerHandler handler){
...配置選項(xiàng)處理...格式化器處理...堆棧無(wú)限引用處理...
handler.sb.Write("Obj:")
WriteObject(model.Obj);//在序列化時(shí)將為Object類(lèi)型做二次真實(shí)類(lèi)型查找
handler.sb.Write("Name:")
WriteString(model.Name);
handler.sb.Write("Age:")
WriteInt(model.Age);
}

如果是List的話, 那么將生成這樣的代碼

handler.sb.Write("[")
foreach(var user in users)
{
WriteUserModel(user);
WriteComma()
}
handler.sb.Write("]")

在當(dāng)前版本中, KoobooJson序列化使用的容器為StringBuilder, 與直接ref char[]相比, 多了一些額外的調(diào)用. 將考慮在下個(gè)版本中構(gòu)建一個(gè)輕便的char容器, 并會(huì)區(qū)分對(duì)象大小, 考慮棧數(shù)組和通過(guò)預(yù)掃描大小來(lái)減少對(duì)內(nèi)存的開(kāi)銷(xiāo),這將顯著提升序列化速度.

反序列化

在對(duì)類(lèi)型進(jìn)行第一次反序列化時(shí), KoobooJson會(huì)為這個(gè)類(lèi)型生成大致是這樣的解析代碼.

UserModel model = JsonSerializer.ToObject("{\"Obj\":3,\"Name\":\"Tom\",\"Age\":18}");void ReadUserModel(string json,JsonDeserializeHandler handler){
...Null處理...
ReadObjLeft()
空元素處理...構(gòu)造函數(shù)處理...配置項(xiàng)處理...格式化器處理...while(i-->0){switch(gechar())
{case 'O':switch(getchar())case 'b':switch(getchar())case 'j':
ReadQuote();
ReadObject();if(getchar()==',')
i++;
}
}
ReadObjRight()
}

KoobooJson生成反序列化代碼, KoobooJson會(huì)假設(shè)json格式完全正確, 沒(méi)有預(yù)先讀取Json結(jié)構(gòu)部分, 而是直接使用代碼來(lái)描述結(jié)構(gòu), 所以KoobooJson少了一次對(duì)json結(jié)構(gòu)的掃描, 執(zhí)行過(guò)程中如果json結(jié)構(gòu)發(fā)生錯(cuò)誤, 會(huì)直接拋出異常.

而對(duì)于key的匹配, KoobooJson生成的是逐個(gè)char的自動(dòng)機(jī)匹配代碼, 目前KoobooJson是以字典樹(shù)為算法, 逐個(gè)char進(jìn)行類(lèi)型比較, 與一次比較多個(gè)char相比, 這種方式顯然沒(méi)有達(dá)到最小的查詢路徑, 不過(guò)在jit優(yōu)化下, 兩種方式實(shí)現(xiàn)經(jīng)測(cè)試效率幾乎一樣.

在反序列化讀取字符時(shí), 因?yàn)槭菍?duì)類(lèi)型動(dòng)態(tài)生成編碼, 提前知道每個(gè)類(lèi)型中的元素的字節(jié)長(zhǎng)度和其類(lèi)型的值長(zhǎng)度, 所以KoobooJson出于更高的性能對(duì)反序列化采取了指針操作, 并加速字節(jié)讀取.

case 3:
if (*(int*)Pointer != *(int*)o) return false;
if (*(Pointer + 2) != *(o + 2)) return false;
goto True;
case 4:
if (*(long*)Pointer != *(long*)o) return false;
goto True;
case 5:
if (*(long*)Pointer != *(long*)o) return false;
if (*(Pointer + 4) != *(o + 4)) return false;

因?yàn)槭侵羔槻僮? KoobooJson在反序列化環(huán)節(jié)幾乎不需要去維護(hù)一個(gè)char池來(lái)存放下一個(gè)需要讀取的json結(jié)構(gòu)片段.

功能介紹

KoobooJson當(dāng)前僅支持3個(gè)API調(diào)用

string Kooboo.Json.JsonSerializer.ToJson(T value, JsonSerializerOption option=null)
T Kooboo.Json.JsonSerializer.ToObject(string json, JsonDeserializeOption option=null)object Kooboo.Json.JsonSerializer.ToObject(string json, Type type, JsonDeserializeOption option=null)

忽略注釋

在json字符串的讀取中KoobooJson會(huì)自動(dòng)忽略注釋

string json = @"
/*注釋*/
{//注釋
/*注釋*/""Name"" /*注釋*/: /*注釋*/""CMS"" /*注釋*/,//注釋
/*注釋*/
""Children"":[//注釋
1/*注釋*/,
2/*注釋*/
]//注釋
}//注釋
/*此處*/
";
var obj = JsonSerializer.ToObject(json);
obj=>Name:CMS
obj=>Children:Array(2)

忽略互引用所導(dǎo)致的堆棧循環(huán)

class A
{
public B b;
}
class B
{
public A a;
}
A.b=B;
B.a=A;

A指向B, B指向A, 在序列化時(shí)這種情況會(huì)發(fā)生無(wú)限循環(huán).可通過(guò)KoobooJson的序列化配置項(xiàng)中的屬性來(lái)設(shè)定這種情況下所對(duì)應(yīng)的結(jié)果

JsonSerializerOption option = new JsonSerializerOption
{
ReferenceLoopHandling = JsonReferenceHandlingEnum.Null
};
string json = JsonSerializer.ToJson(a, option);
json => {\"b\":{\"a\":null}}
------
ReferenceLoopHandling = JsonReferenceHandlingEnum.Empty
json => {\"b\":{\"a\":{}}}
-----
ReferenceLoopHandling = JsonReferenceHandlingEnum.Remove
json => {\"b\":{}}

忽略Null值

class A
{
public string a;
}
A.a=null;
JsonSerializerOption option = new JsonSerializerOption { IsIgnoreValueNull = true };
var json = JsonSerializer.ToJson(A, option);
json => {}

排序特性

class A
{
[JsonOrder(3)]
public int a;
[JsonOrder(2)]
public int b;
[JsonOrder(1)]
public int c;
}

可通過(guò)[JsonOrder(int orderNum)]來(lái)排序序列化的json元素位置. 如果是正常沒(méi)有通過(guò)[JsonOrder]排序元素,那么解析出來(lái)的Json則是默認(rèn)順序:{"a":0,"b":0,"c":0} 上面樣例通過(guò)[JsonOrder]排序后是這樣的:{"c":0,"b":0,"a":0}

忽略序列化元素

class A
{
[IgnoreKey]
public int a;
public int b;
}

可通過(guò)[IgnoreKey]特性來(lái)標(biāo)記序列化和反序列化要忽略的元素 json => {"b":0} 當(dāng)然, 也可以通過(guò)配置來(lái)動(dòng)態(tài)選擇忽略對(duì)象

JsonSerializerOption option = new JsonSerializerOption { IgnoreKeys = new List(){"b"} };var json = JsonSerializer.ToJson(A, option);json => {}

序列化時(shí)僅包含該元素

class A
{
[JsonOnlyInclude]
public int a;
public int b;
public int c;
}
json => {\"a\":0}

如果一個(gè)model里包含幾十個(gè)元素, 而你僅想序列化其中一個(gè), 那么就沒(méi)必要對(duì)每一個(gè)元素進(jìn)行[IgnoreKey]標(biāo)記,只需要對(duì)想要序列化的元素標(biāo)記[JsonOnlyInclude]即可

時(shí)間格式

JsonSerializerOption option = new JsonSerializerOption { DatetimeFormat=DatetimeFormatEnum.ISO8601 };
json => 2012-01-02T03:04:05Z
JsonSerializerOption option = new JsonSerializerOption { DatetimeFormat=DatetimeFormatEnum.RFC1123 };
json => Thu, 10 Apr 2008 13:30:00 GMT
JsonSerializerOption option = new JsonSerializerOption { DatetimeFormat=DatetimeFormatEnum.Microsoft };
json => \/Date(628318530718)\/

首字母大小寫(xiě)

class A
{
public int name;
}
JsonSerializerOption option = new JsonSerializerOption { JsonCharacterRead=JsonCharacterReadStateEnum.InitialUpper };
json => {\"Name\":0}

在對(duì)model序列化時(shí)可以指定key的首字母大小寫(xiě),反序列化時(shí)也可以設(shè)置對(duì)字符串不區(qū)分大小寫(xiě).首字母大小寫(xiě)屬于內(nèi)嵌支持, 在解析時(shí)并不會(huì)影響性能

別名特性

class A
{
[Alias("R01_Name")]
public int name;
}
json => {\"R01_Name\":0}

當(dāng)元素被標(biāo)記[Alias]后,KoobooJson無(wú)論序列化還是反序列化都會(huì)按照Alias來(lái)進(jìn)行解析

反序列化時(shí)指定構(gòu)造函數(shù)

class A
{
public A(){}
[JsonDeserializeCtor(3,"ss")]
public A(int a,string b){}
}

在反序列化的時(shí)候, 我們不得不調(diào)用構(gòu)造函數(shù)來(lái)以此創(chuàng)建對(duì)象. 在常規(guī)情況下, KoobooJson會(huì)通過(guò)優(yōu)先級(jí)自動(dòng)搜索最合適的構(gòu)造函數(shù),其優(yōu)先級(jí)順序?yàn)? public noArgs => private noArgs => public Args => private Args, 這其中, 會(huì)對(duì)有參構(gòu)造函數(shù)進(jìn)行默認(rèn)值構(gòu)造.

然而你也可以顯式通過(guò)[JsonDeserializeCtor(params object[] args)]特性來(lái)指定反序列化時(shí)的構(gòu)造函數(shù), 這樣 當(dāng)KoobooJson創(chuàng)建A實(shí)例的時(shí)候就不是通過(guò)new A(); 而是new A(3,"ss");

值格式化特性

當(dāng)你需要來(lái)覆寫(xiě)由KoobooJson進(jìn)行元素解析的行為時(shí), 我們可以繼承一個(gè) ValueFormatAttribute 來(lái)覆寫(xiě)行為.

class Base64ValueFormatAttribute:ValueFormatAttribute
{
public override string WriteValueFormat(object value,Type type, JsonSerializerHandler handler, out bool isValueFormat){
isValueFormat=true;
if(value==null)
return "null";
else
return ConvertToBase64((byte[])value);
}
public override object ReadValueFormat(string value,Type type, JsonDeserializeHandler handler, out bool isValueFormat){
isValueFormat=true;
if(value=="null")
return null;
else
return Base64Convert(value);
}
}

值格式化特性也可以標(biāo)記在結(jié)構(gòu)體或類(lèi)上, 而另一點(diǎn)是對(duì)于值格式化器, 也可以以全局的方式來(lái)進(jìn)行配置: 以序列化為例, 可通過(guò) JsonSerializerOption中的GlobalValueFormat委托來(lái)進(jìn)行配置

JsonSerializerOption.GlobalValueFormat=(value,type,handler,isValueFormat)=>
{
if(type==typeof(byte[]))
{
isValueFormat=true;
if(value==null)
return "null";
else
return ConvertToBase64((byte[])value);
}
else
{
isValueFormat=false;
return null;
}
}

值得注意的是,對(duì)于byte[]類(lèi)型的base64解析行為, KoobooJson已經(jīng)內(nèi)嵌在配置項(xiàng)中, 只要設(shè)置JsonSerializerOption.IsByteArrayFormatBase64=true即可

全局Key格式化

對(duì)于Model中的Key處理, KoobooJson支持全局的Key格式化器.

class R01_User
{
public string R01_Name;
public int R01_Age;
}

如果我們想把R01這個(gè)前綴給去掉, 只需要注冊(cè)全局Key格式化器的委托即可

JsonSerializerOption.GlobalKeyFormat=(key,parentType,handler)=>
{
if(parentType==typeof(R01_User))
{
return key.Substring(4);
}
return key;
}

這樣,出來(lái)的json是這樣的:{"Name":"","Age":""}

同樣, 對(duì)于反序列化,我們也同樣應(yīng)該注冊(cè):

JsonDeserializeOption.GlobalKeyFormat=(key,parentType)=>
{
if(parentType==typeof(R01_User))
{
return "R01_"+key;
}
return key;
}

推薦閱讀

(點(diǎn)擊標(biāo)題可跳轉(zhuǎn)閱讀)

.NET平臺(tái)功能最強(qiáng)大,性能最佳的JSON庫(kù)

.NET Core/C# 開(kāi)發(fā) IOT 嵌入式設(shè)備

C#凈化版WebAPI框架

看完本文有收獲?請(qǐng)轉(zhuǎn)發(fā)分享給更多人

關(guān)注「DotNet」加星標(biāo),提升.Net技能?

喜歡就點(diǎn)一下「好看」唄~

總結(jié)

以上是生活随笔為你收集整理的c# json datatable_KoobooJson一款高性能且轻量的JSON库的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。