成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從NullObject談C#6.0改進(jìn)

開發(fā) 后端 開發(fā)工具
本文來聊一聊我們經(jīng)常會做的空值檢查問題,從一個簡單的空值檢查Any Where,到設(shè)計模式的NullObjectPattern,再到C#6.0“可能”會提供的語法,讓我們體驗一次語言開發(fā)上的“持續(xù)改進(jìn)”,Let’s go~

[[131771]]

什么是空引用異常

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

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

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

 

  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è)計模式

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

接下來讓我們看看維基百科上的C#實現(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.     } 

 

在C#語言中,我們通過靜態(tài)的擴展方法來實現(xiàn)將檢查方式統(tǒng)一在方法內(nèi)部,而不是寫的到處都是,上面的例子中是在String類上實現(xiàn)了一個SafeGetLength擴展方法,將為所有String類型提供了一個方法,這樣我們在“代碼整潔”上又進(jìn)了一步。

下面我們再來看一個更常用的例子---來自于StackOverFlow

***,說一個細(xì)節(jié)問題,以上代碼均沒有實現(xiàn)“線程安全”,在大牛Eric Lippert的文章中針對線程安全有過一個更精彩的討論,請戳這里

改進(jìn)后的代碼時在方法內(nèi)部增加了一個臨時變量,作為方法內(nèi)部的拷貝,實現(xiàn)線程安全,如果有疑問請參考我的《C#堆vs棧》中對方法內(nèi)部變量在堆棧上的表現(xiàn)一章。

 

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

 

 #p#

更“潮”的方式-C#6.0語法

      來自MSDN Magazine的Mark Michaelis(《C#本質(zhì)論》作者)給我們介紹了C#6.0在語言可能帶來的新改進(jìn),其中就有針對“Null條件運算符”的改進(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 開發(fā)新手,也可能非常熟悉 NullReferenceException。有一個例外是幾乎總是會指出一個 Bug,因為開發(fā)人員在調(diào)用 (null) 對象的成員之前未進(jìn)行充分的 null 檢查。請看看以下示例:

 

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

 

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

 

  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.   Assert.AreEqual<string>(null, Truncate(null42)); 

 

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

 

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

 

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

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

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

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

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

 

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

 

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

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

請注意,null 條件運算符僅可檢索項目,不會分配項目。如果給定 null 集合,那么這意味著什么?

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

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

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

 

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

 

  通過使用 null 條件運算符,整個 set 實現(xiàn)過程就可簡化為:

OnTemperatureChanged?.Invoke(this, value)

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

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

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

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

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

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

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

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

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

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

 示例代碼下載

引用

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

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

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

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

責(zé)任編輯:王雪燕 來源: 博客園
相關(guān)推薦

2011-04-12 16:40:40

C++復(fù)雜度

2010-07-19 09:01:54

.NET 4.0緩存

2011-06-29 18:12:17

2013-08-15 13:29:52

Moco程序庫設(shè)計

2016-04-07 10:33:32

知乎執(zhí)行力

2017-09-27 18:21:36

報表性能集算器

2015-07-02 10:37:32

C#Json字符串類代碼

2010-04-23 09:07:14

2011-07-29 10:32:31

黑莓BBMBBM 6.0

2010-07-23 15:13:11

身份驗證云服務(wù)

2011-12-06 10:04:12

QQ手機移動應(yīng)用應(yīng)用設(shè)計

2014-04-15 13:16:00

Code Review

2020-12-20 10:02:17

ContextReactrender

2010-01-11 11:02:59

Visual C++

2010-01-14 11:07:59

Visual C++

2010-01-21 10:44:59

Visual C++

2020-08-27 07:32:37

MySQL半成品狀態(tài)

2019-09-18 08:53:55

2011-03-03 14:57:00

手機交互設(shè)計產(chǎn)品管理信息架構(gòu)

2012-04-02 19:30:25

webOS
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美精品一区二区三区在线 | 国产成人jvid在线播放 | 国产高清在线 | 精品中文字幕一区 | 成人精品啪啪欧美成 | aaa在线观看 | 日本三级精品 | 精品久久久精品 | 亚洲国产精品一区二区久久 | 亚洲欧美激情国产综合久久久 | 午夜影院在线免费观看视频 | 欧美高清视频 | 精品国产一区二区三区性色 | 中文字幕在线视频一区二区三区 | 国产一区二区观看 | 黄色操视频 | 日本在线一区二区三区 | 日本一区二区三区四区 | 国产精品xxxx | 久久久久久免费毛片精品 | 国产a视频| 一区二区三区四区五区在线视频 | www日本高清视频 | 精品欧美一区免费观看α√ | 国产精品美女久久久久aⅴ国产馆 | www.久草.com | 一区二区片| 日韩α片 | 91中文字幕在线 | av看片| 日韩在线一区二区 | 久久五月婷 | 成人免费在线观看视频 | 夜夜爽99久久国产综合精品女不卡 | 日韩在线精品强乱中文字幕 | 夜夜操操操| 国产成人精品综合 | 日韩欧美精品一区 | 日本在线一区二区 | 黄网站免费观看 | 色一情一乱一伦一区二区三区 |