C# 參數帶this是什麼意思(擴充方法)

黄舟
發布: 2017-02-18 10:24:44
原創
4321 人瀏覽過


擴展方法使你能夠向現有類型「添加」方法,而無需創建新的派生類型、重新編譯或以其他方式修改原始類型。 擴充方法是一種特殊的靜態方法,但可以像擴充類型上的實例方法一樣進行呼叫。  對於 C# 和 Visual Basic 編寫的客戶端程式碼,呼叫擴充方法與呼叫在型別中實際定義的方法之間沒有明顯的差異。

最常見的擴充方法是 LINQ 標準查詢運算符,它將查詢功能加入現有的 System.Collections.IEnumerable 和 System.Collections.Generic.IEnumerable 類型。 若要使用標準查詢運算符,請先使用 using System.Linq 指令將它們置於範圍中。  然後,任何實作了 IEnumerable 的型別看起來都具有 GroupBy、OrderBy、Average 等實例方法。  在 IEnumerable類型的實例(如 List 或 Array)後鍵入「dot」時,可以在 IntelliSense 語句完成中看到這些附加方法。

下面的範例示範如何對一個整數陣列呼叫標準查詢運算子 OrderBy 方法。 括號裡面的表達式是一個 lambda 表達式。  很多標準查詢運算子採用 lambda 運算式作為參數,但這不是擴充方法的必要條件。  有關詳細信息,請參閱 Lambda 表達式(C# 程式指南)。

C#



class ExtensionMethods2    
{    static void Main()
    {            
        int[] ints = { 10, 45, 15, 39, 21, 26 };        var result = ints.OrderBy(g => g);        foreach (var i in result)
        {
            System.Console.Write(i + " ");
        }           
    }        
}//Output: 10 15 21 26 39 45
登入後複製


擴充方法被定義為靜態方法,但它們是透過實例語法進行語法進行的調用。 它們的第一個參數指定方法作用於哪個類型,並且該參數以 this 修飾符為前綴。  只有當你使用 using 指令將命名空間明確匯入到原始碼之後,擴充方法才位於範圍中。

下面的範例示範為 System.String 類別定義的一個擴充方法。 請注意,它是在非巢狀的、非泛型靜態類別內部定義的:

C#


namespace ExtensionMethods
{    public static class MyExtensions
    {        public static int WordCount(this String str)
        {            return str.Split(new char[] { ' ', '.', '?' }, 
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }   
}
登入後複製


於範圍中:

using ExtensionMethods;
登入後複製

而且,可以使用以下语法从应用程序中调用该扩展方法:

string s = "Hello Extension Methods";
int i = s.WordCount();
登入後複製


在代码中,可以使用实例方法语法调用该扩展方法。 但是,编译器生成的中间语言 (IL) 会将代码转换为对静态方法的调用。 因此,并未真正违反封装原则。 实际上,扩展方法无法访问它们所扩展的类型中的私有变量。

有关详细信息,请参阅如何:实现和调用自定义扩展方法(C# 编程指南)。

通常,你更多时候是调用扩展方法而不是实现你自己的扩展方法。 由于扩展方法是使用实例方法语法调用的,因此不需要任何特殊知识即可从客户端代码中使用它们。 若要为特定类型启用扩展方法,只需为在其中定义这些方法的命名空间添加 using 指令。 例如,若要使用标准查询运算符,请将此 using 指令添加到代码中:


using System.Linq;
登入後複製


(你可能还必须添加对 System.Core.dll 的引用。)你将注意到,标准查询运算符现在作为可供大多数 IEnumerable 类型使用的附加方法显示在 IntelliSense 中。

C# 參數帶this是什麼意思(擴充方法)C# 參數帶this是什麼意思(擴充方法)

尽管标准查询运算符没有显示在 String 的 IntelliSense 中,但它们仍然可用。


在編譯時綁定擴充方法

可以使用擴充方法來擴充類別或接口,但不能重寫擴充方法。 與介面或類別方法具有相同名稱和簽署的擴充方法永遠不會被呼叫。  編譯時,擴充方法的優先權總是比型別本身定義的實例方法低。  換句話說,如果某一型別有一個名為 Process(int i) 的方法,而你有一個相同簽章的擴充方法,則編譯器總是綁定到該實例方法。  當編譯器遇到方法呼叫時,它首先在該類型的實例方法中尋找匹配的方法。  如果未找到任何匹配方法,編譯器將搜尋為該類型定義的任何擴充方法,並且綁定到它找到的第一個擴充方法。  下面的範例示範編譯器如何決定要綁定到哪個擴充方法或實例方法。

範例

下面的範例示範 C# 編譯器在決定是將方法呼叫綁定到類型上的實例方法或綁定到擴充方法時所遵循的規則。 靜態類別 Extensions 包含為任何實作了 IMyInterface 的類型定義的擴充方法。  類 AB 和 C 都實現了這個介面。

MethodB 擴充方法永遠不會被調用,因為它的名稱和簽章與這些類別已經實現的方法完全匹配。

如果編譯器找不到具有匹配簽章的實例方法,它會綁定到匹配的擴充方法(如果有這樣的方法)。

C#


// Define an interface named IMyInterface.namespace DefineIMyInterface
{    using System;    public interface IMyInterface
    {        // Any class that implements IMyInterface must define a method
        // that matches the following signature.
        void MethodB();
    }
}// Define extension methods for IMyInterface.namespace Extensions
{    using System;    using DefineIMyInterface;    // The following extension methods can be accessed by instances of any 
    // class that implements IMyInterface.
    public static class Extension
    {        public static void MethodA(this IMyInterface myInterface, int i)
        {
            Console.WriteLine
                ("Extension.MethodA(this IMyInterface myInterface, int i)");
        }        public static void MethodA(this IMyInterface myInterface, string s)
        {
            Console.WriteLine
                ("Extension.MethodA(this IMyInterface myInterface, string s)");
        }        // This method is never called in ExtensionMethodsDemo1, because each 
        // of the three classes A, B, and C implements a method named MethodB
        // that has a matching signature.
        public static void MethodB(this IMyInterface myInterface)
        {
            Console.WriteLine
                ("Extension.MethodB(this IMyInterface myInterface)");
        }
    }
}// Define three classes that implement IMyInterface, and then use them to test// the extension methods.namespace ExtensionMethodsDemo1
{    using System;    using Extensions;    using DefineIMyInterface;    class A : IMyInterface
    {        public void MethodB() { Console.WriteLine("A.MethodB()"); }
    }    class B : IMyInterface
    {        public void MethodB() { Console.WriteLine("B.MethodB()"); }        
    public void MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }
    }    class C : IMyInterface
    {        public void MethodB() { Console.WriteLine("C.MethodB()"); }        
    public void MethodA(object obj)
        {
            Console.WriteLine("C.MethodA(object obj)");
        }
    }    class ExtMethodDemo
    {        static void Main(string[] args)
        {            // Declare an instance of class A, class B, and class C.
            A a = new A();
            B b = new B();
            C c = new C();            // For a, b, and c, call the following methods:
            //      -- MethodA with an int argument
            //      -- MethodA with a string argument
            //      -- MethodB with no argument.

            // A contains no MethodA, so each call to MethodA resolves to 
            // the extension method that has a matching signature.
            a.MethodA(1);           // Extension.MethodA(object, int)
            a.MethodA("hello");     // Extension.MethodA(object, string)

            // A has a method that matches the signature of the following call
            // to MethodB.
            a.MethodB();            // A.MethodB()

            // B has methods that match the signatures of the following
            // method calls.
            b.MethodA(1);           // B.MethodA(int)
            b.MethodB();            // B.MethodB()

            // B has no matching method for the following call, but 
            // class Extension does.
            b.MethodA("hello");     // Extension.MethodA(object, string)

            // C contains an instance method that matches each of the following
            // method calls.
            c.MethodA(1);           // C.MethodA(object)
            c.MethodA("hello");     // C.MethodA(object)
            c.MethodB();            // C.MethodB()
        }
    }
}/* Output:
    Extension.MethodA(this IMyInterface myInterface, int i)
    Extension.MethodA(this IMyInterface myInterface, string s)
    A.MethodB()
    B.MethodA(int i)
    B.MethodB()
    Extension.MethodA(this IMyInterface myInterface, string s)
    C.MethodA(object obj)
    C.MethodA(object obj)
    C.MethodB()
 */
登入後複製

通用准则

通常,建议你只在不得已的情况下才实现扩展方法,并谨慎地实现。 只要有可能,必须扩展现有类型的客户端代码都应该通过创建从现有类型派生的新类型来达到这一目的。 有关详细信息,请参阅继承(C# 编程指南)。

在使用扩展方法来扩展你无法更改其源代码的类型时,你需要承受该类型实现中的更改会导致扩展方法失效的风险。

如果你确实为给定类型实现了扩展方法,请记住以下几点:

  • 如果扩展方法与该类型中定义的方法具有相同的签名,则扩展方法永远不会被调用。

  • 在命名空间级别将扩展方法置于范围中。 例如,如果你在一个名为 Extensions 的命名空间中具有多个包含扩展方法的静态类,则这些扩展方法将全部由 using Extensions; 指令置于范围中。

针对已实现的类库,不应为了避免程序集的版本号递增而使用扩展方法。 如果要向你拥有源代码的库中添加重要功能,应遵循适用于程序集版本控制的标准 .NET Framework 准则。 有关详细信息,请参阅程序集版本控制。

 以上就是C# 参数带this是什么意思(扩展方法)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!