程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#中的擴展方法學習總結

C#中的擴展方法學習總結

編輯:C#入門知識

C#中的擴展方法學習總結


??版權聲明:本文由秦元培創作和發表,采用署名(BY)-非商業性使用(NC)-相同方式共享(SA)國際許可協議進行許可,轉載請注明作者及出處,本文作者為秦元培,本文標題為C#中的擴展方法學習總結,本文鏈接為http://qinyuanpei.com/2015/12/05/extend-methods-of-csharp/.

??各位朋友大家好,我是秦元培,歡迎大家關注我的博客。最近偶然接觸到了C#中的擴展方法,覺得這個語法特性是一個不錯的特性,因此決定在這裡系統地對C#中的擴展方法相關內容進行下總結和整理,因為博主覺得學習這件事情本身就是一個積累的過程,所以博主有時候會對現在的線上培訓和視頻教程這種“在線教育”感到反感。試想《射雕英雄傳》中江南七怪遠赴大漠傳授郭靖武藝苦歷十八載,何以難及全真教丹陽子馬钰傳授內功兩年的積累?這裡固然有郭靖愚笨木讷的天性和江南七怪武功低微的因素,可是在博主看來更重要的是強調了一個積累。想郭靖一生受益自全真教的玄門內功終成一代“為國為民”的俠之大者,則我輩需更加努力方可在這世間行走奔波。

什麼是擴展方法?

??擴展方法從字面上理解是指擴展的方法,而對應到面向對象編程這個格局中則是指為一個類提供的擴展方法。按照我們通常的理解,我們首先需要獲得某個類的源代碼,然後在這個類代碼中增加成員方法,這樣就可以達到為一個類提供擴展方法的目的。可是不幸地是,這種方法在沒有源代碼的情況下就無法奏效了,而且我們人為地去改變源代碼有可能會破壞整個代碼的穩定性。那麼有沒有一種方法能在不改變源代碼的前提下為某個類提供擴展方法呢?這就是我們今天要說的擴展方法,所以我們可以將擴展方法理解為在不改變源代碼的前提下向外部提供擴展方法的一種方式。C#中的擴展方法實現起來是相對來說比較簡單的,例如我們做在Unity3D游戲開發的時候,可能會用到DOTween這個插件。這個插件是iTween的作者重新編寫一個動畫插件,效率上比iTween有較大的提升。更為重要的一點是,它采用擴展方法這種實現方式,使得我們在調用這些API接口的時候難以感覺到我們是在使用一個插件,更像是在使用Unity3D的原生函數,所以當我們使用DOTween + uGUI 這樣的組合的時候,內心會感到無比的舒暢,一切都像是水到渠成一般。

擴展方法有哪些特點?

??擴展方法在實現上和普通的面向對象編程是一樣的,換句話說,我們只需要定義一個類,然後在裡面添加並實現相應的方法即可。但是這裡需要注意的地方有三點,第一,實現擴展方法的類必須是靜態類且類的名稱和實現擴展方法的類無關;第二、實現擴展方法的類方法必須是靜態方法;第三、實現擴展方法的類方法的第一個參數必須是使用this關鍵字指明要實現擴展方法的類。例如,我們知道將一個合法字符串類型轉換為整型,可以使用int.parse()方法,假如我們希望為string類型擴展一個ToInt方法應該怎麼辦呢?我們一起來看下面的這段代碼:

/// 
/// 1、定義一個靜態類
/// 2、靜態類的名稱和要實現擴展方法的具體類無關
/// 
public static class SomeClass
{
    /// 
    /// 3、實現一個具體的靜態方法
    /// 
    ///4、第一個參數必須使用this關鍵字指定要使用擴展方法的類型
    /// 
    public static int ToInt(this string str)
    {
        return int.Parse(str);
    }
}

需要注意的是C#支持擴展方法是從.NET3.5版本開始,所以在編寫擴展方法的時候請確保你的.NET版本是否滿足這一要求。提到版本問題,有很多朋友尤其是從Unity5.0以後開始學習Unity3D的朋友,常常會在我的博客中留言提到我的代碼無法在新環境下運行等等類似地問題,我覺得這個世界上更新速度最快的當屬IT技術了,大家使用新版本沒有問題,可是有時候因為技術發展中的歷史遺留問題例如Python2.7和Python3、Unity4.X和Unity5.X,這個時候可能出現版本不兼容的問題,這個時候如果網絡上的資源沒有及時更新,建議大家還是及時查看官方的最新文檔,因為在博主看來網絡上的書籍或者相關文章都是用來參考的,古話說:盡信書不如無書,只有客觀、冷靜地判斷知識的正確與否,我們方能學到真正有用的知識。

??好了,現在我們編寫完這個擴展方法以後,就可以像下面這樣使用擴展方法了:

string str = "1234";
int val = str.ToInt();

這個示例向大家展示了如何編寫一個無參數的擴展方法,那麼當我們需要在擴展方法中傳入參數的時候該怎麼做呢?我們只需要在第一個參數後繼續加入參數的聲明就好了。例如我們在Unity3D中常常需要給一個3D物體設置坐標,通常我們可以通過下面的代碼來實現:

transform.position = new Vector3(1,1,1);

這個代碼到目前為止是比較簡潔的,可是我們知道在Unity3D中除了position屬性以外還有localPosition屬性,如果我們的代碼中再涉及坐標計算的話,我相信這個代碼一定會變得非常的長。更有甚者,有時候我們只想改變三維坐標中的一個維度,可是我們必須給transform.position一個三維坐標,毫無意外地此時的代碼會變得更長。為了解決這個問題,我們可以擴展出三個方法SetPositionX、SetPositionY、SetPositionZ來分別為x、y、z三個坐標分量進行賦值,我們繼續在SomeClass這個類中添加方法:

/// 
/// 設置Tranform的X坐標
/// 
///當前Transform
///X坐標
public static void SetPositionX(this Transform tran, float x)
{
    tran.position = new Vector3(x, tran.position.y, tran.position.z);
}

/// 
/// 設置Tranform的Y坐標
/// 
///當前Transform
///Y坐標
public static void SetPositionY(this Transform tran, float y)
{
    tran.position = new Vector3(tran.position.x, y, tran.position.z);
}

/// 
/// 設置Tranform的Z坐標
/// 
///當前Transform
///Z坐標
public static void SetPositionZ(this Transform tran, float z)
{
    tran.position = new Vector3(tran.position.x, tran.position.y, z);
}

同樣的,我們現在可以直接為一個三維物體的坐標進行賦值:

transform.SetPositionX(1.0f);
transform.SetPositionY(1.0f);
transform.SetPositionZ(1.0f);

使用擴展方法的利弊

??擴展方法使用起來得心應手,所以我們這裡來討論下使用擴展方法的利弊。好處當然是自由而任性地使用擴展方法對類進行擴展,而且擴展方法在Visual Studio中的智能提示會以藍色向下箭頭進行標識。擴展方法的壞處則是要看設計擴展方法的人能否較好的駕馭這個特性啦,其實所有的技術都是一樣的,我常常在游戲群裡聽到人鄙視Unity3D引擎,以UnReal Engine4為游戲引擎世界裡的泰山北斗,我承認UE4的畫面效果好,可是能真正用好這個引擎的人有多少呢?擴展方法在使用的時候應該遵守就近原則,即是在最小的范圍內使用擴展方法,對具體類而非抽象類實現擴展方法。我們使用擴展方法無非是因為它在邏輯層需要這樣的功能,所以我們沒有必要去改變抽象層的邏輯,因為這樣會“污染”整個代碼。舉一個簡單的例子,我們知道.NET中的基類是object,如果我們對這個類進行擴展,毫無疑問它會影響所有繼承自object的類,這樣就會造成“污染”,顯然是不可取的。

小結

在C#中實現擴展方法的類必須是靜態類且類的名稱和實現擴展方法的類無關 實現擴展方法的類方法必須是靜態方法 實現擴展方法的類方法的第一個參數必須是使用this關鍵字指明要實現擴展方法的類 實現擴展方法應遵守就近原則,在最小的范圍內使用擴展方法以避免造成“污染”

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved