日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
從NullObject談C#6.0改進(jìn)

什么是空引用異常

創(chuàng)新互聯(lián)主要從事網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)千陽(yáng),十年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):18982081108

作為一個(gè)敲過(guò)代碼的碼農(nóng)來(lái)說(shuō),似乎沒(méi)有誰(shuí)沒(méi)有遇到過(guò)NullReferenceException這 個(gè)問(wèn)題,有些時(shí)候當(dāng)方法內(nèi)部調(diào)用一個(gè)屬性、方法(委托)時(shí),我們控制這些屬性在“外部”的表現(xiàn)(當(dāng)然某些情況下使用ref關(guān)鍵字除外),所以我們要在方法 的內(nèi)部去判斷屬性、委托方法是否為Null來(lái)避免可能的、錯(cuò)誤使用上帶來(lái)的空引用異常,這樣當(dāng)我們知道如果對(duì)象為Null的話,我們會(huì)實(shí)現(xiàn)符合我們“預(yù) 期”的行為。

解決空引用異常---Check Any Where

這很簡(jiǎn)單,我只要在需要用的地方檢查一下是否為Null就可以了。是的,這非常簡(jiǎn)單,語(yǔ)義也很清晰,但是當(dāng)你要重復(fù)檢查一個(gè)對(duì)象實(shí)體10000萬(wàn)次時(shí),你的代碼中將存在10000個(gè)如下代碼段:

  
 
  1. public void Check()
  2.         {
  3.             if (Person.AlivePerson() != null)
  4.             {
  5.                 Person.AlivePerson().KeepAlive = true;
  6.             } 
  7.         }

你能容忍這樣的行為嗎?

         If(OK)

                   Continue;

         Else

                   Close;

應(yīng)用NullObject設(shè)計(jì)模式

NullObjectPattern出自forth by Gamma(設(shè)計(jì)模式4人組),核心內(nèi)容是:提供一個(gè)給定對(duì)象的空值代理,空值代理中提供不做任何事情的方法實(shí)現(xiàn)。

接下來(lái)讓我們看看維基百科上的C#實(shí)現(xiàn):

  
 
  1. // compile as Console Application, requires C# 3.0 or higher
  2. using System;
  3. using System.Linq;
  4. namespace MyExtensionWithExample {
  5.     public static class StringExtensions { 
  6.         public static int SafeGetLength(this string valueOrNull) { 
  7.             return (valueOrNull ?? string.Empty).Length; 
  8.         }
  9.     }
  10.     public static class Program {
  11.         // define some strings
  12.         static readonly string[] strings = new [] { "Mr X.", "Katrien Duck", null, "Q" };
  13.         // write the total length of all the strings in the array
  14.         public static void Main(string[] args) {
  15.             var query = from text in strings select text.SafeGetLength(); // no need to do any checks here
  16.             Console.WriteLine(query.Sum());
  17.         // The output will be: 18 
  18.         }
  19.     }
  20. }

在C#語(yǔ)言中,我們通過(guò)靜態(tài)的擴(kuò)展方法來(lái)實(shí)現(xiàn)將檢查方式統(tǒng)一在方法內(nèi)部,而不是寫(xiě)的到處都是,上面的例子中是在String類上實(shí)現(xiàn)了一個(gè)SafeGetLength擴(kuò)展方法,將為所有String類型提供了一個(gè)方法,這樣我們?cè)凇按a整潔”上又進(jìn)了一步。

下面我們?cè)賮?lái)看一個(gè)更常用的例子---來(lái)自于StackOverFlow

  
 
  1. public static class EventExtensions
  2.     {
  3.         public static void Raise(this EventHandler evnt, object sender, T args)
  4.             where T : EventArgs
  5.         {
  6.             if (evnt != null)
  7.             {
  8.                 evnt(sender, args);
  9.             }
  10.         }
  11.     }

***,說(shuō)一個(gè)細(xì)節(jié)問(wèn)題,以上代碼均沒(méi)有實(shí)現(xiàn)“線程安全”,在大牛Eric Lippert的文章中針對(duì)線程安全有過(guò)一個(gè)更精彩的討論,請(qǐng)戳這里。

改進(jìn)后的代碼時(shí)在方法內(nèi)部增加了一個(gè)臨時(shí)變量,作為方法內(nèi)部的拷貝,實(shí)現(xiàn)線程安全,如果有疑問(wèn)請(qǐng)參考我的《C#堆vs?!分袑?duì)方法內(nèi)部變量在堆棧上的表現(xiàn)一章。

  
 
  1. public class SomeClass
  2.     {
  3.         public event EventHandler MyEvent;
  4.         private void DoSomething()
  5.         {
  6.             var tmp = MyEvent;
  7.             tmp.Raise(this, EventArgs.Empty);
  8.         }
  9.     }

#p#

更“潮”的方式-C#6.0語(yǔ)法

      來(lái)自MSDN Magazine的Mark Michaelis(《C#本質(zhì)論》作者)給我們介紹了C#6.0在語(yǔ)言可能帶來(lái)的新改進(jìn),其中就有針對(duì)“Null條件運(yùn)算符”的改進(jìn)。

  C#6.0更多參考:

  Part One: https://msdn.microsoft.com/zh-cn/magazine/dn683793.aspx

  Part Two: https://msdn.microsoft.com/zh-cn/magazine/dn802602.aspx

  即使是 .NET 開(kāi)發(fā)新手,也可能非常熟悉 NullReferenceException。有一個(gè)例外是幾乎總是會(huì)指出一個(gè) Bug,因?yàn)殚_(kāi)發(fā)人員在調(diào)用 (null) 對(duì)象的成員之前未進(jìn)行充分的 null 檢查。請(qǐng)看看以下示例:

  
 
  1. public static string Truncate(string value, int length)
  2. {
  3.   string result = value;
  4.   if (value != null) // Skip empty string check for elucidation
  5.   {
  6.     result = value.Substring(0, Math.Min(value.Length, length));
  7.   }
  8.   return result;
  9. }

如果不進(jìn)行 null 檢查,此方法會(huì)引發(fā) NullReferenceException。盡管這很簡(jiǎn)單,但檢查字符串參數(shù)是否為 null 的過(guò)程卻稍微有些繁瑣。通常,考慮到比較的頻率,該繁瑣的方法可能沒(méi)有必要。C# 6.0 包括一個(gè)新的 null 條件運(yùn)算符,可幫助您更加簡(jiǎn)便地編寫(xiě)這些檢查:

  
 
  1. public static string Truncate(string value, int length)
  2. {          
  3.   return value?.Substring(0, Math.Min(value.Length, length));
  4. }
  5. [TestMethod]
  6. public void Truncate_WithNull_ReturnsNull()
  7. {
  8.   Assert.AreEqual(null, Truncate(null, 42));
  9. }

根據(jù) Truncate_WithNull_ReturnsNull 方法所演示的內(nèi)容,如果對(duì)象的值實(shí)際上為 null,則 null 條件運(yùn)算符將返回 null。這帶來(lái)了一個(gè)問(wèn)題,即 null 條件運(yùn)算符在調(diào)用鏈中出現(xiàn)時(shí)會(huì)是什么情況?如以下示例中所示:

  
 
  1. public static string AdjustWidth(string value, int length)
  2. {
  3.   return value?.Substring(0, Math.Min(value.Length, length)).PadRight(length);
  4. }
  5. [TestMethod]
  6. public void AdjustWidth_GivenInigoMontoya42_ReturnsInigoMontoyaExtended()
  7. {
  8.   Assert.AreEqual(42, AdjustWidth("Inigo Montoya", 42).Length);
  9. }

盡管 Substring 是通過(guò) null 條件運(yùn)算符進(jìn)行調(diào)用的,并且 null value?.Substring 似乎返回了 null,但語(yǔ)言行為按您的想法進(jìn)行。這簡(jiǎn)化了對(duì) PadRight 的調(diào)用過(guò)程,并立即返回 null,從而避免會(huì)導(dǎo)致出現(xiàn) NullReferenceException 的編程錯(cuò)誤。這個(gè)概念稱為“null 傳播”。

Null 條件運(yùn)算符會(huì)根據(jù)具體條件進(jìn)行 null 檢查,然后再調(diào)用目標(biāo)方法以及調(diào)用鏈中的所有其他方法。這將可能產(chǎn)生一個(gè)令人驚訝的結(jié)果,例如,text?.Length.GetType 語(yǔ)句中的結(jié)果。

如果 null 條件運(yùn)算符在調(diào)用目標(biāo)為 null 時(shí)返回 null,那么調(diào)用會(huì)返回值類型的成員時(shí)最終會(huì)是什么數(shù)據(jù)類型(假定值類型不能為 null)?例如,從 value?.Length 返回的數(shù)據(jù)類型不能只是 int。答案當(dāng)然是:可以為 null 的類型(int?)。實(shí)際上,嘗試僅將結(jié)果分配給 int 將會(huì)出現(xiàn)編譯錯(cuò)誤:

int length = text?.Length; // Compile Error: Cannot implicitly convert type 'int?' to 'int'

Null 條件具有兩種語(yǔ)法形式。首先,問(wèn)號(hào)在點(diǎn)運(yùn)算符前面 (?.)。其次,將問(wèn)號(hào)和索引運(yùn)算符結(jié)合使用。例如,給定一個(gè)集合(而非在索引到集合之前顯式進(jìn)行 null 檢查),您就可以使用 null 條件運(yùn)算符執(zhí)行此操作:

  
 
  1. public static IEnumerable GetValueTypeItems(
  2.   IList collection, params int[] indexes)
  3.   where T : struct
  4. {
  5.   foreach (int index in indexes)
  6.   {
  7.     T? item = collection?[index];
  8.     if (item != null) yield return (T)item;
  9.   }
  10. }

  此示例使用了運(yùn)算符 ?[…] 的 null 條件索引形式,導(dǎo)致僅在集合不為 null 時(shí)才索引到集合。通過(guò) null 條件運(yùn)算符的此形式,T? item = collection?[index] 語(yǔ)句在行為上相當(dāng)于:

T? item = (collection != null) ? collection[index] : null.

請(qǐng)注意,null 條件運(yùn)算符僅可檢索項(xiàng)目,不會(huì)分配項(xiàng)目。如果給定 null 集合,那么這意味著什么?

請(qǐng)注意針對(duì)引用類型使用 ?[…] 時(shí)的隱式歧義。由于引用類型可以為 null,因此對(duì)于集合是否為 null,或者是否元素本身實(shí)際上就是 null 而言,來(lái)自 ?[…] 運(yùn)算符的 null 結(jié)果不明確。

Null 條件運(yùn)算符的一個(gè)非常有用的應(yīng)用程序解決了 C# 自 C# 1.0 以來(lái)一直存在的的一個(gè)特性,即在調(diào)用委托之前檢查是否為 null。我們來(lái)看一下中顯示的 C# 2.0 代碼。

  圖 1 在調(diào)用委托之前檢查是否為 Null

  
 
  1. class Theremostat
  2. {
  3.   event EventHandler OnTemperatureChanged;
  4.   private int _Temperature;
  5.   public int Temperature
  6.   {
  7.     get
  8.     {
  9.       return _Temperature;
  10.     }
  11.     set
  12.     {
  13.       // If there are any subscribers, then
  14.       // notify them of changes in temperature
  15.       EventHandler localOnChanged =
  16.         OnTemperatureChanged;
  17.       if (localOnChanged != null)
  18.       {
  19.         _Temperature = value;
  20.         // Call subscribers
  21.         localOnChanged(this, value);
  22.       }
  23.     }
  24.   }
  25. }

  通過(guò)使用 null 條件運(yùn)算符,整個(gè) set 實(shí)現(xiàn)過(guò)程就可簡(jiǎn)化為:

OnTemperatureChanged?.Invoke(this, value)

  現(xiàn)在,您只需對(duì)將 null 條件運(yùn)算符作為前綴的 Invoke 進(jìn)行調(diào)用,不再需要將委托實(shí)例分配給本地變量,從而實(shí)現(xiàn)線程安全,甚至是在調(diào)用委托之前顯式檢查值是否為 null。

C# 開(kāi)發(fā)人員都很想知道在***的四個(gè)版本中是否對(duì)此內(nèi)容有所改進(jìn)。答案是最終進(jìn)行了改進(jìn)。僅此一項(xiàng)功能就可以改變調(diào)用委托的方式。

另一個(gè) null 條件運(yùn)算符普及的常見(jiàn)模式是與 coalesce 運(yùn)算符結(jié)合使用。您無(wú)需在調(diào)用 Length 之前對(duì) linesOfCode 進(jìn)行 null 檢查,而是可以編寫(xiě)項(xiàng)目計(jì)數(shù)算法,如下所示:

List linesOfCode = ParseSourceCodeFile("Program.cs"); return linesOfCode?.Count ?? 0;

在這種情況下,任何空集合(無(wú)項(xiàng)目)和 null 集合均標(biāo)準(zhǔn)化為返回相同數(shù)量??傊?,null 條件運(yùn)算符將實(shí)現(xiàn)以下功能:

  1. 如果操作數(shù)為 null,則返回 null

  2. 如果操作數(shù)為 null,則簡(jiǎn)化調(diào)用鏈中的其他調(diào)用

  3. 如果目標(biāo)成員返回一個(gè)值類型,則返回可以為 null 的類型 (System.Nullable)。

  4. 以線程安全的方式支持委托調(diào)用

  5. 可用作成員運(yùn)算符 (?.) 和索引運(yùn)算符 (?[…])

 示例代碼下載

引用

http://stackoverflow.com/questions/13629051/net-event-raising-and-nullobject-pattern ---線程安全的擴(kuò)展機(jī)制

https://msdn.microsoft.com/zh-cn/magazine/dn802602.aspx ---C#6.0 Null條件運(yùn)算符

http://en.wikipedia.org/wiki/Null_Object_pattern ---維基百科上的NullObjectPattern解釋

作者:Stephen Cui
出處:http://www.cnblogs.com/cuiyansong


新聞名稱:從NullObject談C#6.0改進(jìn)
文章URL:http://www.5511xx.com/article/dpheoog.html