亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#6 null 條件運算符

2020-01-24 01:03:40
字體:
來源:轉載
供稿:網友

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為何會被編譯成支持多態方式調用的callvirt,在這種情況下貌似call效率會更高一些,但是終究"?."和"?:"編譯的代碼沒有本質差異。

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

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        //比較前兩步加載的值。如果第一個值大于第二個值,則將整數值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                 //返回 }

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

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

3. Example 3.1 ?[

null條件運算符不但可以使用?.的語法訪問對象的屬性和方法,還可以用?[ 的語法訪問檢測數組或包含索引器的對象是否是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))); }

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

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

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

4. 總結

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久一区二区三区| 欧美日韩日本国产| 亚洲精品丝袜日韩| 亚洲va码欧洲m码| 欧美激情一区二区三区在线视频观看| 91chinesevideo永久地址| 91经典在线视频| 高清视频欧美一级| 亚洲成人999| 中文日韩在线视频| 欧美激情在线观看| 91香蕉嫩草影院入口| 97精品久久久中文字幕免费| 美日韩精品视频免费看| 中文字幕日韩av| 91情侣偷在线精品国产| 亚洲欧美中文另类| 国产在线观看91精品一区| 日韩在线视频网| 国产精品久久久| 久久99精品视频一区97| 亚洲在线观看视频网站| 色噜噜久久综合伊人一本| 欧美亚洲激情在线| 久久久亚洲国产天美传媒修理工| 亚洲毛片在线免费观看| 亚洲高清免费观看高清完整版| 国产精品尤物福利片在线观看| 国产不卡一区二区在线播放| 亚洲欧洲国产精品| 久久中国妇女中文字幕| 色青青草原桃花久久综合| 亚洲免费视频观看| 中文字幕精品www乱入免费视频| 久久久久久久久久久亚洲| 91免费人成网站在线观看18| 欧美夫妻性生活视频| 91午夜在线播放| 国产国产精品人在线视| www日韩欧美| 久久久女人电视剧免费播放下载| 国内精品视频久久| 国产精品免费看久久久香蕉| 亚洲黄色在线观看| 亚洲一区二区久久久| 91久久国产精品| 亚洲精品mp4| 日韩福利在线播放| 成人免费大片黄在线播放| 国产精品99蜜臀久久不卡二区| 欧美性在线观看| 欧美自拍视频在线观看| 97在线日本国产| 国产欧美韩国高清| 亚洲已满18点击进入在线看片| 欧洲午夜精品久久久| 欧美xxxx综合视频| 日韩精品一二三四区| 国产精品电影久久久久电影网| 亚洲精品自拍偷拍| 三级精品视频久久久久| 成人国产精品日本在线| 亚洲午夜色婷婷在线| 成人黄色片在线| 成人h视频在线观看播放| 久久综合国产精品台湾中文娱乐网| 在线视频欧美性高潮| 国产suv精品一区二区| 日韩av在线最新| 日韩高清av在线| 日本成人在线视频网址| 亚洲国产精彩中文乱码av| 九九精品在线视频| 亚洲人成网在线播放| 欧美一级视频在线观看| 97av在线视频| 国产91在线高潮白浆在线观看| 伊人久久男人天堂| 国产成人一区二区三区小说| 国产一区视频在线| 久久免费成人精品视频| 精品自拍视频在线观看| 亚洲高清色综合| 成人福利在线视频| 国产精品久久一| 欧美在线观看网站| 国产精品一区二区三| 亚洲人成人99网站| 日韩免费在线视频| 92国产精品视频| 7777精品视频| 国产一区深夜福利| 欧洲午夜精品久久久| 91sao在线观看国产| 欧美日韩性视频在线| 亚洲欧美日韩国产中文专区| 亚洲欧洲偷拍精品| 欧美在线视频播放| 亚洲色图av在线| 亚洲综合成人婷婷小说| 国产精品免费看久久久香蕉| 97人洗澡人人免费公开视频碰碰碰| 日韩av电影在线免费播放| 亚洲国产精品久久久久秋霞不卡| 国产精品久久久久影院日本| 2021久久精品国产99国产精品| 国产精品免费视频久久久| 国产在线999| www.精品av.com| 91精品国产自产在线老师啪| 国产精品爽黄69天堂a| 曰本色欧美视频在线| 91中文字幕一区| 亚洲精品在线观看www| 午夜精品美女自拍福到在线| 欧美极品少妇xxxxⅹ喷水| 日韩动漫免费观看电视剧高清| 国产精品久久久久秋霞鲁丝| 国产精品黄色影片导航在线观看| www.亚洲一区| 色综久久综合桃花网| 国产激情综合五月久久| 久久人人97超碰精品888| 国产成人精品a视频一区www| 国产日韩在线观看av| 日韩精品极品毛片系列视频| 国产日韩欧美在线看| 日韩女优人人人人射在线视频| 日韩美女在线观看| 国产精品入口夜色视频大尺度| 国产精品视频一| 久久人人爽人人爽人人片av高清| 色播久久人人爽人人爽人人片视av| 日韩欧美成人区| 日韩国产精品亚洲а∨天堂免| 久久伊人精品一区二区三区| 欧美巨乳美女视频| 国产中文日韩欧美| 亚洲精品电影在线| 色悠久久久久综合先锋影音下载| 成人av在线天堂| 久久婷婷国产麻豆91天堂| 成人黄色片网站| 亚洲日本中文字幕免费在线不卡| 国产在线98福利播放视频| 国产亚洲欧美aaaa| 色偷偷噜噜噜亚洲男人| 操91在线视频| 欧美亚洲国产日韩2020| 精品毛片三在线观看| 日韩精品视频免费在线观看| 国产一区二区三区中文| 国模视频一区二区| 亚洲区一区二区| 国产精品电影在线观看| 欧美日韩免费在线观看| 98精品在线视频| 欧美视频一区二区三区…| 欧美激情综合色综合啪啪五月| 久久国产精品影视| 亚洲国产女人aaa毛片在线| 午夜精品视频在线| 欧美裸体男粗大视频在线观看| 九九综合九九综合|