擴展方法從簡單應用到深入解析,讀這一篇文章就夠了


前言(扯淡-_-)

大家好,今天和大家聊聊擴展的事,我將帶着大家從簡單應用開始深入理解擴展方法的原理,並對擴展方法的使用給出合理的建議。

在實際應用中,當我們在使用某類時發現類中缺少我們想要的方法,最簡單直接的就是修改類的源代碼來添加我們想要的方法。但事實往往不如人意,總會因為各種因素不可以直接修改源碼:拿不到源碼、不允許修改,這時候通過繼承並擴展的方式來復用是再好不過了,但是如果連最后的繼承的權利都剝奪的話(密封類不允許繼承)?...這時候就需要用到【擴展方法】了。

擴展方法簡介

我們先來看看理論(大家不要急,待會就上代碼):
擴展方法是C#3.0中引入的新特性,它可以向類中添加新方法,而不需要使用繼承來創建新類,也不需要修改原有的類。使用原有類型對象的實例即可直接調用新方法。

它必須符合以下要求(重要):

  1. 必須是定義在靜態類中的靜態方法;
  2. 第一個參數的類型是要擴展的類型;
  3. 第一個參數需要添加this關鍵字以標識其為擴展方法。


簡單應用

我們用string類型來舉個例子:string類中有很多方法,比如常用的a.ToString();

現在我們想給string類添加一個方法,用來獲取字符串中包含多少個單詞

先看看這兩種做法:

一、直接新建方法(通用,但不是給string類添加新方法,這里寫出來用於比較) 

public class Tool
{

public static int GetWordCount(string str)
{
return str.Split(new char[]{' ',',','?'},StringSplitOptions.RemoveEmptyEntries).Length;
}
}
調用:
string s="myTest string. yeyeye";
int count=Tool.GetWordCount(s);

直接在工具類Tool中建了一個GetWordCount方法,直接傳值調用


二、繼承的方式(注意:String類不允許被繼承這里用來比較)   

public class MyString:String
{
public int GetWordCount()
{
return this.Split(new char[]{' ',',','?'},StringSplitOptions.RemoveEmptyEntries).Length;
}
}
調用:
MyString s="myTest string. yeyeye";
int count=s.GetWordCount();

 

三、擴展方法的方式
除了以上兩種方法 ,還有什么方式呢?接下來我們來看看不使用繼承給string類添加一個方法? 

public static class MyExtension
{
public static int GetWordCount(this string str)
{
return str.Split(new char[]{' ',',','?'},StringSplitOptions.RemoveEmptyEntries).Length;
}
}

調用:

string s="myTest string. yeyeye";
int count=s.GetWordCount();

如上 ;這就是一個擴展方法,注意紅色標記的3個位置,靜態類中的靜態方法通過this關鍵字標識類型。


我們來比較一下;

  1. 第一種方式是比較通用的一種方式,也是通常情況下使用最多的,但和擴展方法比較來說,代碼的可讀性不如擴展方法。
  2. 繼承的方式是一個很好的擴展方案,但有時不一定是完美的,比如:a. 每次繼承都會產生新類,且使用時需要進行相應的強制轉換(string=>MyString),b. 有些類本身設計為密封類,是不允許被繼承的,如上所使用的例子string是不允許被繼承的,所以第二種方案是不可行的。這時,第三種方案擴展方法就派上用場了。


我們再來看看擴展方法的使用: 

public static class MyExtension
{
public static int GetWordCount(this string str)
{
return str.Split(new char[]{' ',',','?'},StringSplitOptions.RemoveEmptyEntries).Length;
}
}
調用:

string s="myTest string. yeyeye";
int count=s.GetWordCount();、

注意:我們只有引用了MyExtension所在命名空間后才可以使用新擴展的方法。

看到這 ,我相信大家都已經能熟練使用擴展方法了吧,現在我們就來深入理解一下擴展方法的原理。

 

深入理解擴展方法

下面是摘自CSDN-simonezhlx的分析並進行整理:如下:擴展方法StringToUpper,使用s實例可直接使用新擴展的方法

我們先來看看通過Reflector反編譯回來的IL代碼:

如你所看到的,IL中的擴展方法調用已經被解釋成了一個簡單的靜態方法調用。這意味着什么?

擴展方法不過是種更簡單調用靜態方法的手段而已,使代碼寫起來更自然。換言之,最終編譯器還是將擴展方法轉化成靜態類的靜態方法調用
既然編譯后轉換成了靜態方法調用的方式,那么編譯器又是如何辨別這是一個擴展方法呢?繼續看下面:

可以看到我們寫的擴展方法在編譯中被解釋成了包含指定特性(ExtensionAttribute)的靜態方法,該特性使編譯器清楚該方法實際上是個擴展方法

 

我們如何辨別是否是擴展方法?

擴展方法通過如下辨別:

       1.藍色箭頭 

       2.包含(extension)的提示信息

你可能使用過的擴展方法:

如果你使用過Linq,你會發現Linq和擴展方法的關系原來是如此密切!

這么多藍色箭頭,呵呵了....

 

擴展方法的幾點總結

  1. 可以向類中添加新方法,而不需要使用繼承來創建新類,也不需要修改原有的類;
  2. 如果擴展方法與類中的方法有相同的簽名,則擴展方法不會被調用,即:擴展方法會被被擴展類的同名方法覆蓋,所以實現擴展方法我們需要承擔隨時被覆蓋的風險(例如:如果擴展一個string類中的ToString(), 這時候擴展方法是無效的);
  3. 擴展方法不能訪問被擴展類的私有成員
  4. 擴展方法只能使用實例來調用,不能像普通的靜態方法一樣使用類名調用;
  5. 只有引入擴展方法所在的命名空間后,擴展方法才可以使用。

擴展方法特性的使用選擇
微軟公司提供的文檔中提到:“通常,建議您只在不得已的情況下才實現擴展方法,並謹慎的實現。只要有可能,必須擴展現有類型的客戶端代碼都應該通過創建從現有類型派生的新類型來達到這一目的。"
但是,通過我們的一些實例分析來看,擴展方法在某些特定的場合應該是優選的方案。如果你的類庫本身功能很完善,能夠滿足絕大部分的應用,只是針對某個領域、行業或特殊應用進行一系列功能擴展,我們可以使用擴展方法將這些功能進行組織,得到一個專用的擴展方法庫,在不改變庫代碼的情況下為庫增加可選的新功能。

這就猶如筆記本電腦的USB一樣,不需要將所有的功能點都集成到電腦上,我們只需要將內存,硬盤等大家都需要的功能集成就可以,通過USB擴展其他的新功能設備,通過擴展方法來實現滿足對個別用戶的需求的功能點。


關於擴展類型就分享到這了,大家在使用時靈活運用就可以了。相關資源獲取或其他疑問可在微信公眾號CodeL留言。

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com