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

首頁(yè) > 編程 > C# > 正文

C#6 null 條件運(yùn)算符

2019-10-29 21:24:38
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

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;   }  } } }

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

2. null條件運(yùn)算符

 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判斷和簡(jiǎn)化三元運(yùn)算符的使用,簡(jiǎn)潔到不能再簡(jiǎn)潔了吧。按照慣例,上兩份IL代碼對(duì)比對(duì)比。

老版本的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

新語(yǔ)法的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條件運(yùn)算符版的IL

咦,貌似有很大不一樣,我們?cè)賮?lái)一份三元運(yùn)算符版的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

三元運(yùn)算符版的IL

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

但是和if判斷的相比簡(jiǎn)化了一些,我們分析下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對(duì)象。 IL_0003: ldnull        //加載null IL_0004: stloc.1        //把null放入索引為1的變量,也就是name對(duì)象。 IL_0005: ldloc.0        //加載索引為0的位置的變量,也就是person對(duì)象 IL_0006: ldnull        //加載null IL_0007: cgt.un        //比較前兩步加載的值。如果第一個(gè)值大于第二個(gè)值,則將整數(shù)值1推送到計(jì)算堆棧上;反之,將0推送到計(jì)算堆棧上。 IL_0009: stloc.2        //把比較結(jié)果放入索引為2的變量中,也就是V_2對(duì)象 IL_000a: ldloc.2        //加載索引為2的對(duì)象,也就是V_2對(duì)象 IL_000b: brfalse.s IL_0016     //如果上一步加載的對(duì)象為false、空引用或零,則跳轉(zhuǎn)到IL_0016位置,也就是結(jié)束當(dāng)前方法。 IL_000d: nop         //空 IL_000e: ldloc.0        //加載索引為0的位置的變量,也就是person對(duì)象 IL_000f: callvirt instance string csharp6.Person::get_Name() //調(diào)用person對(duì)象的get_Name方法。 IL_0014: stloc.1        //把上一步的結(jié)果存入索引為1的變量中,也就是name對(duì)象。 IL_0015: nop         //空 IL_0016: ret         //返回 } 

null條件運(yùn)算符版的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對(duì)象  IL_0003: ldloc.0               //加載索引為0的位置的變量,也就是person對(duì)象  IL_0004: brtrue.s  IL_0009          //如果上一步加載的對(duì)象為true、非空引用或非零,則跳轉(zhuǎn)到IL_0009位置  IL_0006: ldnull                //加載null  IL_0007: br.s    IL_000f          //無(wú)條件的跳轉(zhuǎn)到IL_000f處  IL_0009: ldloc.0               //加載索引為0的位置的變量,也就是person對(duì)象  IL_000a: call    instance string csharp6.Person::get_Name() ////調(diào)用person對(duì)象的get_Name方法。  IL_000f: stloc.1               //把上一步的結(jié)果存入索引為1的變量中,也就是name對(duì)象。  IL_0010: ret                 //返回 }

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

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

3. Example 3.1 ?[

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

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

3.2 ?.結(jié)合??

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

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

3.3 以線程安全的方式調(diào)用事件

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

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

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

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

4. 總結(jié)

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

 

注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到c#教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 旬阳县| 荔浦县| 同江市| 平江县| 佛坪县| 通山县| 建德市| 西青区| 马尔康县| 双流县| 蓬安县| 合肥市| 蕲春县| 呼和浩特市| 梁山县| 武定县| 柳林县| 阳山县| 子洲县| 绥德县| 祁连县| 台安县| 清流县| 修水县| 鹤壁市| 连云港市| 鹤峰县| 靖安县| 突泉县| 开鲁县| 阆中市| 兴城市| 利川市| 琼海市| 介休市| 孟州市| 莱芜市| 达拉特旗| 兴文县| 云霄县| 饶阳县|