国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

C#中ValueTuple的原理詳解

2019-10-29 19:59:05
字體:
供稿:網(wǎng)友

前言

本文告訴大家一些 ValueTuple 的原理,避免在使用出現(xiàn)和期望不相同的值。ValueTuple 是 C# 7 的語法糖,如果使用的 .net Framework 是 4.7 以前,那么需要使用 Nuget 安裝System.ValueTuple

雖然 ValueTuple 的很好用,但是需要知道他有兩個(gè)地方都是在用的時(shí)候需要知道他原理。如果不知道原理,可能就發(fā)現(xiàn)代碼和預(yù)期不相同

json 轉(zhuǎn)換

先創(chuàng)建一個(gè)項(xiàng)目,然后安裝 Json 解析,使用下面的代碼,在運(yùn)行之前,先猜一下,下面的代碼會出現(xiàn)什么

   var foo = (name: "lindexi", site: "blog.csdn.net/lindexi_gd");   var str = JsonConvert.SerializeObject(foo);

實(shí)際上輸出的是 {"Item1":"lindexi","Item2":"blog.csdn.net/lindexi_gd"}

C#,ValueTuple

那么剛才的命名在哪?

如果想知道,那么請看 ValueTuple 的原理

原理

先來寫一段代碼,編譯之后對他反編譯,看一下他是怎么做的

  static void Main(string[] args)  {   var foo = Foo();   var str = JsonConvert.SerializeObject(foo);   Console.WriteLine(str);  }  static (string name, string site) Foo()  {   return (name: "lindexi", site: "blog.csdn.net/lindexi_gd");  }

不需要安裝反編譯軟件,可以使用這個(gè)網(wǎng)站拿到反編譯

可以看到Foo被編譯為 TupleElementNames 特性的兩個(gè)字符串

 [return: TupleElementNames(new string[] {  "name",  "site" })] private static ValueTuple<string, string> Foo() {  return new ValueTuple<string, string>("lindexi", "blog.csdn.net/lindexi_gd"); }

所以實(shí)際上代碼是 ValueTuple<string, string> 不是剛才定義的代碼,只是通過 TupleElementNames 讓編譯器知道值,所以是語法糖。

IL 代碼是

private hidebysig static valuetype [mscorlib]System.ValueTuple`2<string, string>  Foo() cil managed  { .param [0]  .custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[])   = (  01 00 02 00 00 00 04 6e 61 6d 65 04 73 69 74 65 // .......name.site 這里就是 return: TupleElementNames 的命名  00 00           // ..  ) .maxstack 2 .locals init (  [0] valuetype [mscorlib]System.ValueTuple`2<string, string> V_0 ) // [20 9 - 20 10] IL_0000: nop    // [21 13 - 21 72] IL_0001: ldstr  "lindexi" IL_0006: ldstr  "blog.csdn.net/lindexi_gd" IL_000b: newobj  instance void valuetype [mscorlib]System.ValueTuple`2<string, string>::.ctor(!0/*string*/, !1/*string*/) IL_0010: stloc.0  // V_0 IL_0011: br.s   IL_0013 // [22 9 - 22 10] IL_0013: ldloc.0  // V_0 IL_0014: ret    }

這個(gè)特性只有編譯器可以用,不可以在代碼使用。

在上面的解釋,實(shí)際上 IL 不知道存在定義的命名,所以不可以通過這個(gè)方法獲得值。

動態(tài)類型獲得值

如果希望使用動態(tài)類型獲得值,那么下面的代碼實(shí)際上會運(yùn)行出現(xiàn)異常

  static void Main(string[] args)  {   dynamic foo = Foo();   Console.WriteLine(foo.name);  }  static (string name, string site) Foo()  {   return (name: "lindexi", site: "blog.csdn.net/lindexi_gd");  }

運(yùn)行出現(xiàn) RuntimeBinderException 異常,因?yàn)闆]有發(fā)現(xiàn) name 屬性

實(shí)際上對比下面匿名類,也就是很差不多寫法。

  dynamic foo = new { name = "lindexi", site = "blog.csdn.net/lindexi_gd" };   Console.WriteLine(foo.name);

運(yùn)行是可以的,所以在使用動態(tài)類型,請不要使用 ValueTuple ,如果需要使用,那么請知道有存在找不到變量異常,而且是在運(yùn)行才出現(xiàn)異常。

性能提升

如果使用 ValueTuple 編程會有一些優(yōu)點(diǎn),性能是其中之一。而且對于異步編程,使用 ValueTuple 可以繼續(xù)使用 await 的方法。

假如有一個(gè)方法需要返回 5 個(gè)參數(shù),那么以前的做法有三個(gè)方法,第一個(gè)方法是使用 out 的方法,第二個(gè)方法是使用 Tuple ,第三個(gè)方法是定義一個(gè)臨時(shí)的類。

如果使用了 out 的方法,那么這個(gè)方法就不可以繼續(xù)使用異步 await 的方法,因?yàn)?await 需要做出狀態(tài)機(jī),參見我寫的await原理。如果使用 Tuple ,或這定義一個(gè)臨時(shí)的類,就會出現(xiàn)性能的問題。

從上面的原理,已經(jīng)告訴大家,ValueTuple 是值類型,而 Tuple 或定義的一個(gè)類不是值類型。編譯器的優(yōu)化是讓 ValueTuple 分配在棧,對于普通的類分配在堆空間。如果一個(gè)類分配到堆空間,那么就需要使用垃圾回收才可以清理空間。而分配到棧就不需要使用垃圾回收,使用完成就清空棧,效率比堆空間大。

但是使用棧空間需要注意,棧空間是很小的,如果使用了大量棧空間可能會出現(xiàn)堆棧gg。因?yàn)榭紤]到部分剛?cè)腴T的小伙伴,所以我就需要多說一些,上面說的 ValueTuple 使用了棧空間需要小心棧空間不足,和你存放的值的關(guān)系不大,而是和定義的 ValueTuple 數(shù)量有關(guān),這個(gè)數(shù)量是非常大的。但是在遞歸方法中,本來是剛好空間足夠的,在使用了 ValueTuple 可能就不夠了。

使用 ValueTuple 可以繼續(xù)使用異步,而且不需要垃圾回收,性能比Tuple高,所以建議在多返回參數(shù)使用 ValueTuple,而不是定義一個(gè)類。

其他需要知道的

不要隨便定義一個(gè)看不懂的值

實(shí)際上下面的代碼,編譯是可以通過

(int x, (int y, (float a, float b))[] c) f1

但是這個(gè)值,在看的時(shí)候,幾乎說不出他的屬性

第二個(gè)需要知道的,ValueTuple 是值類型,所以他的默認(rèn)值不是 null 而是 default(xx),在C# 7.2 支持使用關(guān)鍵字,所以不需要去寫 defalut(xx,xx)

關(guān)于 ValueTuple 變量名的定義也是很難說的,有的小伙伴覺得需要使用 Axx 的方式命名,但是很多小伙伴覺得使用 aaBa 的命名更好,所以暫時(shí)對于他的命名使用 aaBa 的方法,大家覺得什么方式好請告訴我

參見: Exploring Tuples as a Library Author

C# 7: Dynamic types and Reflection cannot access Tuple fields by name

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網(wǎng)的支持。


注:相關(guān)教程知識閱讀請移步到c#教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 军事| 济阳县| 偏关县| 庄浪县| 绵阳市| 德州市| 繁峙县| 娱乐| 古田县| 郴州市| 金山区| 仙游县| 许昌市| 深州市| 汝州市| 清远市| 基隆市| 温泉县| 三都| 中牟县| 洞口县| 东乡| 广南县| 独山县| 竹溪县| 罗定市| 公主岭市| 斗六市| 女性| 城口县| 临朐县| 滦南县| 宁津县| 乐都县| 沈阳市| 柏乡县| 富川| 连南| 武川县| 惠东县| 乐至县|