[易學C#]C#3.0語言新特性之擴充方法

來源:互聯網
上載者:User

http://kenchell.blog.163.com/blog/static/26088309200971611491146/

當我們需要對已有類的功能進行擴充時,我們通常會想到繼承,繼承已有類,然後為其加入新的行為。而C# 3.0中加入的擴充方法(Extension Methods)特性,則提供了另一種實現功能擴充的方式。

擴充方法是一種特殊的靜態方法,它定義在一個靜態類中,但可以在其他類的對象上像調用執行個體方法那樣進行調用。因此,通過擴充方法,我們就可以在不修改一個類型的前提下對一個類型進行功能上的擴充,這種方法並不會產生新的類型,而是採用向已有類中加入新方法的方式來完成功能擴充;同時,也可以將一些近似的類型中近似的功能同一實現在一個類中,便於閱讀和維護。從最終效果上看,擴充方法使得擴充一個現有類型和構造一個具有附加方法的類型變成了現實。

20.3.1 定義擴充方法

在對已有類進行擴充時,我們需將所有擴充方法都寫在一個靜態類中,這個靜態類就相當於存放擴充方法的容器,所有的擴充方法都可以寫在這裡面。

而且擴充方法採用一種全新的聲明方式:

public static 傳回型別 擴充方法名(this 要擴充的類型 參數名稱 [,擴充方法參數列表]),

與普通方法聲明方式不同,擴充方法的第一個參數以this關鍵字開始,後跟被擴充的類型名,然後才是真正的參數列表。如下面的樣本是一個聲明了兩個擴充方法的靜態類:

namespace C20_1

{

    public static class Extensions

    {

       public static int ToInt32(this string s)

        {

            return Int32.Parse(s);

        }

        public static T[] Slice<T>(this T[] source, int index, int count)

        {

            if (index < 0 || count < 0 || source.Length - index < count)

            {

                throw new ArgumentException("Argument Error Information.");

            }

            T[] result = new T[count];

            Array.Copy(source, index, result, 0, count);

            return result;

        }

    }

}

在上面的樣本中,靜態Extensions類中有兩個擴充方法,如方法ToInt32是對string類的擴充,它為string類加入了名為ToInt32的方法,該方法沒有參數,並返回一個int類型的值,它將完成數字字元向整數的轉換。有了這個擴充方法之後,就可對任意string類的對象調用ToInt32方法了,該方法就像其本身定義的一樣。

其實,擴充方法和正常的靜態方法具有完全相同的功能。另外,一旦匯入了擴充方法,就可以用調用執行個體方法的文法來調用擴充方法。

20.3.2 匯入擴充方法

擴充方法使用using匯入命名空間指令來匯入。除了匯入一個命名空間中的類型以外,一個using匯入命名空間指令還可以匯入一個命名空間中所有的靜態類中所有的擴充方法。最後,匯入的擴充方法表現為其第一個參數的類型的附加方法,並且其優先順序比一般的執行個體方法低。例如,我們可以使用using匯入命名空間指令匯入了上面例子中的C20_1命名空間:

using C20_1

匯入擴充方法之後,我們就可以這樣來調用它了。代碼如下所示:

static void Main(string[] args)

 {

      string s = "1000";

      int i = s.ToInt32();   // 和Extensions.ToInt32(s)一樣

      int[] digits = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

      int[] a = digits.Slice(4, 3); // 和Extensions.Slice(digits, 4, 3)一樣

 }

20.3.3 調用擴充方法

下面描述了擴充方法調用的詳細規則。在下面這些形式的方法調用中:

expr . identifier ()

expr . identifier (args)

expr . identifier <typeargs>()

expr . identifier <typeargs>(args)

如果按照正常的過程沒有發現可用的執行個體方法(確切地說,當待調用的候選方法集合為空白時),就會嘗試構造一個擴充方法調用。這些方法調用首先被重寫為下面相應的形式:

identifier (expr)

identifier (expr,args)

identifier <typeargs>(expr)

identifier <typeargs>(expr,args)

然後將重寫後的形式作為一個靜態方法調用進行處理,identifier按照下列順序進行解析:

首先是命名空間生命中最接近的聲明,然後是每一個接近的命名空間,最後是包含這些代碼的編譯單元,其間不斷嘗試重寫過的方法調用,這些方法來自一個方法組,該組由using匯入命名空間指令匯入的命名空間中所有可見的identifier所提供的可見的擴充方法構成。第一個產生了非空候選方法集合的方法組是對沖洗過的方法調用的一個選擇。如果所有的嘗試都產生了空的候選方法集合,就會出現一個編譯期錯誤。

上述規則意味著執行個體方法的優先順序勝於擴充方法,並且最後引入的命名空間中的擴充方法的優先順序勝於較先引入的命名空間中的擴充方法。例如:

using N1;

namespace N1

{

    public static class E

    {

        public static void F(this object obj, int i) { }

        public static void F(this object obj, string s) { }

    }

}

class A { }

class B

{

    public void F(int i) { }

}

class C

{

    public void F(object obj) { }

}

class G

{

    static void Test(A a, B b, C c)

    {

        a.F(1);           // E.F(object, int)

        a.F("Hello");    // E.F(object, string)

        b.F(1);           // B.F(int)

        b.F("Hello");    // E.F(object, string)

        c.F(1);           // C.F(object)

        c.F("Hello");    // C.F(object)

    }

}

在這個例子中,B的方法優先於第一個擴充方法,而C的方法優先於所有兩個擴充方法。

20.3.4 擴充方法使用注意事項

通常,建議你只在不得已的情況下才實現擴充方法,並謹慎地實現。只要有可能,必須擴充現有類型的用戶端代碼都應該通過建立從現有類型派生的新類型來達到這一目的。

在使用擴充方法來擴充您無法更改其原始碼的類型時,你需要承受該類型實現中的更改會導致擴充方法失效的風險。如果你確實為給定類型實現了擴充方法,請注意如下幾點:

l         擴充方法是給現有類型添加一個方法;

l         擴充方法是通過指定關鍵字this修飾方法的第一個參數;

l         擴充方法必須聲明在靜態類中;

l         擴充方法只能針對執行個體調用;

l         如果擴充方法與該類型中定義的方法具有相同的簽名,則擴充方法永遠不會被調用;

l         擴充方法被在命名空間層級放入範圍中。例如,如果你在同一個名為Extensions的命名空間中具有多個包含擴充方法的靜態類,則這些擴充方法將全部由using Extensions指令放入範圍中。

l         擴充方法有他的優先順序,現有執行個體的方法的優先順序最高,其次為最近的namespace下的擴充方法,最後為較遠namespace下的擴充方法。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.