我還記得剛剛學編程的時候,老師經(jīng)常會提到一句話:注意空指針。所以經(jīng)常在某些“入口”位置,進行代碼校驗,空指針的判斷就是其中的一項工作。
string類型作為常用的數(shù)據(jù)類型,它在項目中出現(xiàn)的機率極高,所以往往會有如下的代碼片段:
// str 是 string 類型 if (str == null || str == string.Empty) { // ... 其他操作 return; }每次都寫兩個雙等號判斷,著實有點煩人,讓人苦惱不已。在接下來的一段時間內(nèi)有幸發(fā)現(xiàn)了一種新的寫法:
// str 是 string 類型 if (string.IsNullOrEmpty(str)) { // ... 其他操作 return; }可是有些地方還要判斷是否為空格...
// str 是 string 類型 if (String.IsNullOrEmpty(str) || str.Trim().Length == 0) { // ... 其他操作 return; }代碼長度又變長了...慢著,別急,.NET 4.0來了...
// str 是 string 類型 if (String.IsNullOrWhiteSpace(str)) { // ... 其他操作 return; }該方法很強大,不僅可以判斷空格,而且可以判斷制表符 '/t' 等空白字符。
可是... 可是... 我還是覺得不舒服,如果能實現(xiàn)下面的效果該多好呢。
string str = null; bool result = str.IsEmpty(); Console.WriteLine(result); // 正常編譯通過,正常運行不發(fā)生異常,并且輸出 True
假設(shè),我們已經(jīng)通過某些手段使string對象擁有IsEmpty方法:
如果IsEmpty是實例化方法,str對象為null,此時調(diào)用方法必定會引發(fā)空指針異常。
如果IsEmpty是靜態(tài)方法,按照語法規(guī)則,對象是無法調(diào)用靜態(tài)方法的。
所以,這條路好像行不通啊,怎么辦呢?——讓擴展方法來解決吧。
C#編程指南——擴展方法,給出的說明:擴展方法使你能夠向現(xiàn)有類型“添加”方法,而無需創(chuàng)建新的派生類型、重新編譯或以其他方式修改原始類型。
擴展方法是一種特殊的靜態(tài)方法,但可以像擴展類型上的實例方法一樣進行調(diào)用。
看樣子擴展方法很強大啊,那我們該如何實現(xiàn)和調(diào)用自定義的擴展方法呢?
1、因為擴展方法是向現(xiàn)有類型“添加”方法,所以必須有一個類型,這里就是我們想要添加方法的string類型了。
2、擴展方法也是方法,方法總是需要“載體”的,所以我們需要一個類。對該類的要求有且僅有兩點:
1)是頂級非泛型靜態(tài)類,2)是對于客戶代碼而言要有足夠的訪問權(quán)限。
3、對于擴展方法的要求有四點,除了是靜態(tài)方法和對于客戶代碼而言擁有足夠的訪問權(quán)限之外,還要求:
1)擴展方法的第一個參數(shù)必須是將要擴展的類型,這里就是string類型了。2)有且僅有第一個參數(shù)必須以this修飾符開頭。
4、寫完擴展方法,引入相應(yīng)的命名空間(如果需要),根據(jù)VS的智能敏感提示,然后寫代碼調(diào)用即可。
Demo:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MethodDemo{ public static class StringExtentsion { public static bool IsEmpty(this string str) { return string.IsNullOrWhiteSpace(str); } } class PRogram { static void Main(string[] args) { string[] arr = new string[] { null, string.Empty, " ", " /t ", " /r/n " }; foreach (string str in arr) { bool result = str.IsEmpty(); Console.WriteLine(result); // 編譯通過,運行無異常,并且全部輸出True } Console.Read(); } }}
讓我們仔細看一下這個demo吧,哇塞,對象竟然可以調(diào)用靜態(tài)方法了,這完全打破了以往的語法規(guī)則啊。是這樣嗎?讓我們以懷疑的心態(tài)一探究竟。
我們利用 VS自帶的IL反匯編程序,反編譯一下,看一看MSIL代碼。StringExtentsion類的IsEmpty方法簽名如下:
.method public hidebysig static bool IsEmpty(string str) cil managed {} 我們可以從中找到熟悉的影子 public static bool IsEmpty(string str){},它和一個標準的靜態(tài)方法無異,this 修飾符在這時候已經(jīng) “消失” 了。再看一下客戶代碼吧:
IL_003b: call bool MethodDemo.StringExtentsion::IsEmpty(string)
即便你看不懂MSIL代碼,我想你也有可能推測出正確結(jié)果——沒錯,我們被編譯器“欺騙”了,以下兩種寫法是等效的:
result = str.IsEmpty(); result = StringExtentsion.IsEmpty(str); // 此時 擴展方法中的this修飾符是可有可無的
看到這里,對擴展方法已經(jīng)有了一個大概了解,我們再回頭看一下 C#編程指南——擴展方法,中給出的一句說明:
擴展方法使你能夠向現(xiàn)有類型“添加”方法,而無需創(chuàng)建新的派生類型、重新編譯或以其他方式修改原始類型。擴展方法是一
種特殊的靜態(tài)方法,但可以像擴展類型上的實例方法一樣進行調(diào)用。
1、在這里“添加”兩個字被加了雙引號,故名其意不是真正的添加,擴展方法還存在于其定義的靜態(tài)類中,編譯后的方法簽名和標準的靜態(tài)方法無差異,
this修飾符、在這時候已經(jīng)消失了。
2、擴展方法是一種特殊的靜態(tài)方法,其特殊在于其語法規(guī)則可保證編譯器可以將“擴展類型的對象調(diào)用靜態(tài)方法(擴展方法)”這種語法表象 編譯通過。
可以想象一下,編譯器在編譯的時候,它要查找當前代碼文件域所引入的命名空間下的所有擴展方法、其工作量是很大的(更多參見:ExtensionAttribute)。
后記:
1、這次舉的這個例子很特殊,能將擴展方法的絕對威力展示出來:
1)string是.NET 類庫中的類,我們不能修改string類吧。
2)string是密封類,不能繼承。
3)避免空指針異常,按語法規(guī)則最便捷的方式就是通過靜態(tài)方法的參數(shù)去解決,就像 string.IsNullOrWhiteSpace 方法一樣,
可是想得到的形式卻是對象調(diào)用實例方法。
2、如果給object添加一個擴展方法會出現(xiàn)什么效果呢?(未完待續(xù)...)
新聞熱點
疑難解答