最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#6 null 條件運算符

 更新時間:2016年07月05日 17:06:36   投稿:lqh  
本文主要對比C# 6 null運算符與老版本的不同,并且用代碼實例測試,發(fā)現(xiàn)新語法性能提高,語法簡化了。希望看到的同學對你有所幫助

1. 老版本的代碼

 namespace csharp6
 {
  internal class Person
  {
   public string Name { get; set; }
  }
 
  internal class Program
  {
   private static void Main()
   {
   Person person = null;
   string name = null;
   if (person != null)
   {
    name = person.Name;
   }
  }
 }
 }

 在我們使用一個對象的屬性的時候,有時候第一步需要做的事情是先判斷這個對象本身是不是bull,不然的話你可能會得到一個System.NullReferenceException 的異常。雖然有時候我們可以使用三元運算符string name = person != null ? person.Name : null;來簡化代碼,但是這種書寫方式還是不夠簡單......由于null值檢測時編程中非常常用的一種編碼行為,so,C#6為我們帶來了一種更為簡化的方式。

2. null條件運算符

 namespace csharp6
 {
  internal class Person
  {
   public string Name { get; set; }
  }
 
  internal class Program
  {
   private static void Main()
   {
    Person person = null;
   string name = person?.Name;
  }
  }
 }

從上面我們可以看出,使用?. 這種方式可以代替if判斷和簡化三元運算符的使用,簡潔到不能再簡潔了吧。按照慣例,上兩份IL代碼對比對比。

老版本的IL代碼:

.method private hidebysig static void Main() cil managed
 {
 .entrypoint
 // Code size  23 (0x17)
 .maxstack 2
 .locals init ([0] class csharp6.Person person,
    [1] string name,
    [2] bool V_2)
 IL_0000: nop
 IL_0001: ldnull
 IL_0002: stloc.0
 IL_0003: ldnull
 IL_0004: stloc.1
 IL_0005: ldloc.0
 IL_0006: ldnull
 IL_0007: cgt.un
 IL_0009: stloc.2
 IL_000a: ldloc.2
 IL_000b: brfalse.s IL_0016
 IL_000d: nop
 IL_000e: ldloc.0
 IL_000f: callvirt instance string csharp6.Person::get_Name()
 IL_0014: stloc.1
 IL_0015: nop
 IL_0016: ret
 } // end of method Program::Main

if版的IL

新語法的IL:

.method private hidebysig static void Main() cil managed
 {
 .entrypoint
 // Code size  17 (0x11)
 .maxstack 1
 .locals init ([0] class csharp6.Person person,
    [1] string name)
 IL_0000: nop
 IL_0001: ldnull
 IL_0002: stloc.0
 IL_0003: ldloc.0
 IL_0004: brtrue.s IL_0009
 IL_0006: ldnull
 IL_0007: br.s  IL_000f
 IL_0009: ldloc.0
 IL_000a: call  instance string csharp6.Person::get_Name()
 IL_000f: stloc.1
 IL_0010: ret
 } // end of method Program::Main

null條件運算符版的IL

咦,貌似有很大不一樣,我們再來一份三元運算符版的IL看看:

 .method private hidebysig static void Main() cil managed
 {
 .entrypoint
 // Code size  17 (0x11)
 .maxstack 1
 .locals init ([0] class csharp6.Person person,
    [1] string name)
 IL_0000: nop
 IL_0001: ldnull
 IL_0002: stloc.0
 IL_0003: ldloc.0
 IL_0004: brtrue.s IL_0009
 IL_0006: ldnull
 IL_0007: br.s  IL_000f
 IL_0009: ldloc.0
 IL_000a: callvirt instance string csharp6.Person::get_Name()
 IL_000f: stloc.1
 IL_0010: ret
 } // end of method Program::Main

三元運算符版的IL

新語法"?."和三元運算符"?:"的結果是唯一的差別是IL_000a這一行。"?."的方式被編譯為call,而"?:"的方式被編譯為callvirt,不知為何"?:"中的persion.Name為何會被編譯成支持多態(tài)方式調用的callvirt,在這種情況下貌似call效率會更高一些,但是終究"?."和"?:"編譯的代碼沒有本質差異。

但是和if判斷的相比簡化了一些,我們分析下IL,看看有哪些差異(這里就忽略call和callvirt的區(qū)別了):

if版的IL分析:

.method private hidebysig static void Main() cil managed
 {
 .entrypoint
 .maxstack 2
 .locals init ([0] class csharp6.Person person, //初始化局部變量person,把person放在索引為0的位置
   [1] string name,      //初始化局部變量name,把name放在索引為1的位置
   [2] bool V_2)       //初始化局部變量V_2,把V_2放在索引為2的位置
 IL_0000: nop         //空
 IL_0001: ldnull        //加載null
 IL_0002: stloc.0        //把null放入索引為0的變量,也就是person對象。
 IL_0003: ldnull        //加載null
 IL_0004: stloc.1        //把null放入索引為1的變量,也就是name對象。
 IL_0005: ldloc.0        //加載索引為0的位置的變量,也就是person對象
 IL_0006: ldnull        //加載null
 IL_0007: cgt.un        //比較前兩步加載的值。如果第一個值大于第二個值,則將整數(shù)值1推送到計算堆棧上;反之,將0推送到計算堆棧上。
 IL_0009: stloc.2        //把比較結果放入索引為2的變量中,也就是V_2對象
 IL_000a: ldloc.2        //加載索引為2的對象,也就是V_2對象
 IL_000b: brfalse.s IL_0016     //如果上一步加載的對象為false、空引用或零,則跳轉到IL_0016位置,也就是結束當前方法。
 IL_000d: nop         //空
 IL_000e: ldloc.0        //加載索引為0的位置的變量,也就是person對象
 IL_000f: callvirt instance string csharp6.Person::get_Name() //調用person對象的get_Name方法。
 IL_0014: stloc.1        //把上一步的結果存入索引為1的變量中,也就是name對象。
 IL_0015: nop         //空
 IL_0016: ret         //返回
 } 

null條件運算符版的IL分析:

 .method private hidebysig static void Main() cil managed
 {
  .entrypoint
  .maxstack 1
  .locals init ([0] class csharp6.Person person, //初始化局部變量person,把person放在索引為0的位置
       [1] string name)           //初始化局部變量name,把name放在索引為1的位置
  IL_0000: nop                 //空
  IL_0001: ldnull                //加載null
  IL_0002: stloc.0               //把null放入索引為0的變量,也就是person對象
  IL_0003: ldloc.0               //加載索引為0的位置的變量,也就是person對象
  IL_0004: brtrue.s  IL_0009          //如果上一步加載的對象為true、非空引用或非零,則跳轉到IL_0009位置
  IL_0006: ldnull                //加載null
  IL_0007: br.s    IL_000f          //無條件的跳轉到IL_000f處
  IL_0009: ldloc.0               //加載索引為0的位置的變量,也就是person對象
  IL_000a: call    instance string csharp6.Person::get_Name() ////調用person對象的get_Name方法。
  IL_000f: stloc.1               //把上一步的結果存入索引為1的變量中,也就是name對象。
  IL_0010: ret                 //返回
 }

通過分析我們發(fā)現(xiàn),null運算符編譯后的IL代碼更簡短,使用了2個分支跳轉,簡化了判斷邏輯,而if版的IL還多出來一個bool類型的V_2臨時變量。

so,結論就是"?."的和三元運算符"?:"的編譯結果是一樣的,而且簡化了if的判斷。所以不管是從性能還是可讀性方面考慮,"?."都是推薦的寫法。

3. Example 3.1 ?[

null條件運算符不但可以使用?.的語法訪問對象的屬性和方法,還可以用?[ 的語法訪問檢測數(shù)組或包含索引器的對象是否是null。比如:

 Person[] persons = null;
 //?.
 int? length = persons?.Length;
 //?[
 Person first = persons?[0];

3.2 ?.結合??

上面的persions?.Lenght返回的結果是Nullable類型的,有時候我們可能需要的是一個int類型的,那么我們可以結合空連接運算符"??"一起使用,比如:

 Person[] persons = null;
 //?.和??結合使用
 int length = persons?.Length ?? 0;

3.3 以線程安全的方式調用事件

 PropertyChangedEventHandler propertyChanged = PropertyChanged;
 if (propertyChanged != null)
 {
 propertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
 }

上面的代碼一直是我們調用事件的處理方式,把事件的引用放到一個臨時變量中是為了防止在調用這個委托的時候,事件被取消注冊,產(chǎn)生null的情況。

我們從C#6以后終于可以用更簡單的方式去觸發(fā)事件調用了(這個埂自從C#1時代一直延續(xù)至今...):

 PropertyChanged?.Invoke(propertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));

4. 總結

null條件運算符是一種語法簡化,同時也會做一種編譯優(yōu)化,優(yōu)化方式和三元運算符的優(yōu)化效果是一致的。語法更簡化了,性能也更好了,我們有什么理由不用新語法呢。

相關文章

  • c# winform treelistview的使用(treegridview)實例詳解

    c# winform treelistview的使用(treegridview)實例詳解

    這篇文章主要介紹了c# winform treelistview的使用(treegridview),本文通過實例代碼給大家詳細介紹,需要的朋友可以參考下
    2017-12-12
  • C#堆排序實現(xiàn)方法

    C#堆排序實現(xiàn)方法

    這篇文章主要介紹了C#堆排序實現(xiàn)方法,實例分析了C#對排序的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • C#使用Streamwriter打開文件的方法

    C#使用Streamwriter打開文件的方法

    這篇文章主要介紹了C#使用Streamwriter打開文件的方法,涉及C#操作文件的技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04
  • C#編程中最容易犯的7種編寫錯誤分享

    C#編程中最容易犯的7種編寫錯誤分享

    編程時犯錯是必然的,這篇文章主要和大家來分享7個C#編程中最容易犯的7種編寫錯誤,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2023-03-03
  • C#實現(xiàn)tostring轉換成16進制的方法

    C#實現(xiàn)tostring轉換成16進制的方法

    本文介紹了在C#中將整數(shù)、字節(jié)數(shù)組、字符串轉換為十六進制字符串,以及將十六進制字符串轉換回整數(shù)的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-02-02
  • C#多線程基礎知識匯總

    C#多線程基礎知識匯總

    這篇文章主要介紹了C#多線程基礎知識的相關資料,文中示例代碼非常詳細,幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-07-07
  • C# 多線程中經(jīng)常訪問同一資源可能造成哪些問題

    C# 多線程中經(jīng)常訪問同一資源可能造成哪些問題

    這篇文章主要介紹了C# 多線程中經(jīng)常訪問同一資源可能造成哪些問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • winform實現(xiàn)拖動文件到窗體上的方法

    winform實現(xiàn)拖動文件到窗體上的方法

    這篇文章主要介紹了winform實現(xiàn)拖動文件到窗體上的方法,以實例分析了C#中WinForm操作窗體及文件的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-09-09
  • Audio Source組件及相關API

    Audio Source組件及相關API

    這篇文章主要介紹了Audio Source組件及相關API的相關知識,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-11-11
  • C#中BitConverter.ToUInt16()和BitConverter.ToString()的簡單使用

    C#中BitConverter.ToUInt16()和BitConverter.ToString()的簡單使用

    這篇文章主要介紹了C#中BitConverter.ToUInt16()和BitConverter.ToString()的簡單使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02

最新評論

略阳县| 汉寿县| 诸暨市| 万年县| 平乡县| 来凤县| 宜君县| 花莲市| 阳信县| 南开区| 六盘水市| 郯城县| 同心县| 临城县| 平安县| 页游| 邢台县| 盐山县| 永胜县| 中江县| 治县。| 定州市| 广丰县| 肇源县| 大英县| 通州区| 寿宁县| 苍溪县| 岳普湖县| 晴隆县| 上杭县| 方山县| 六盘水市| 灵石县| 吉首市| 西和县| 亚东县| 天台县| 临泽县| 滁州市| 萨迦县|