Heim  >  Artikel  >  Backend-Entwicklung  >  Was bedeutet der C#-Parameter dabei (Erweiterungsmethode)?

Was bedeutet der C#-Parameter dabei (Erweiterungsmethode)?

黄舟
黄舟Original
2017-02-18 10:24:444344Durchsuche


Erweiterungsmethoden ermöglichen es Ihnen, Methoden zu einem vorhandenen Typ „hinzufügen“, ohne einen neuen abgeleiteten Typ erstellen, neu kompilieren oder den ursprünglichen Typ anderweitig ändern zu müssen. Eine Erweiterungsmethode ist eine spezielle Art statischer Methode, kann jedoch wie eine Instanzmethode für einen Erweiterungstyp aufgerufen werden. Bei in C# und Visual Basic geschriebenem Clientcode gibt es keinen wesentlichen Unterschied zwischen dem Aufruf einer Erweiterungsmethode und dem Aufruf der tatsächlich im Typ definierten Methode.

Die gebräuchlichste Erweiterungsmethode ist der LINQ-Standardabfrageoperator, der den vorhandenen Typen System.Collections.IEnumerable und System.Collections.Generic.IEnumerable Abfragefunktionen hinzufügt. Um die Standardabfrageoperatoren zu verwenden, verwenden Sie zunächst using Die System.Linq-Direktive ordnet sie dem Gültigkeitsbereich zu. Dann scheint jeder Typ, der IEnumerable implementiert, Instanzmethoden wie GroupBy, OrderBy, Average usw. zu haben. Wenn Sie „Punkt“ nach einer Instanz des Typs IEnumerable eingeben (z. B. List oder Array), können Sie Folgendes tun: Diese zusätzlichen Methoden werden bei der Vervollständigung der IntelliSense-Anweisung angezeigt.

Das folgende Beispiel zeigt, wie die Standardabfrageoperator-Methode OrderBy für ein Array von Ganzzahlen aufgerufen wird. Der Ausdruck in den Klammern ist ein Lambda-Ausdruck. Viele Standardabfrageoperatoren akzeptieren Lambda-Ausdrücke als Parameter, dies ist jedoch keine Voraussetzung für Erweiterungsmethoden. Weitere Informationen finden Sie unter Lambda Ausdrücke (C#-Programmierhandbuch).

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


Erweiterung Methoden werden als statische Methoden definiert, aber sie werden über die Instanzmethodensyntax aufgerufen. Ihr erster Parameter gibt an, mit welchem ​​Typ die Methode arbeitet, und dem Parameter wird der Modifikator this vorangestellt. Erweiterungsmethoden liegen nur dann im Gültigkeitsbereich, wenn Sie den Namespace mithilfe der Direktive using explizit in Ihren Quellcode importieren.

Das folgende Beispiel zeigt eine Erweiterungsmethode, die für die System.String-Klasse definiert ist. Beachten Sie, dass es innerhalb einer nicht verschachtelten, nicht generischen statischen Klasse definiert ist:

C#


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


Die Erweiterungsmethode WordCount kann mit dieser using-Direktive in den Gültigkeitsbereich eingefügt werden:

using ExtensionMethods;


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

string s = "Hello Extension Methods";
int i = s.WordCount();


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

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

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


using System.Linq;


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

Was bedeutet der C#-Parameter dabei (Erweiterungsmethode)?Was bedeutet der C#-Parameter dabei (Erweiterungsmethode)?

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


Erweiterungsmethoden zur Kompilierungszeit binden

Erweiterungsmethoden können zum Erweitern einer Klasse oder Schnittstelle verwendet werden , Erweiterungsmethoden können jedoch nicht überschrieben werden. Eine Erweiterungsmethode mit demselben Namen und derselben Signatur wie eine Schnittstelle oder Klassenmethode wird niemals aufgerufen. Beim Kompilieren haben Erweiterungsmethoden immer eine niedrigere Priorität als im Typ selbst definierte Instanzmethoden. Mit anderen Worten, wenn ein Typ eine Methode namens Process(int i)-Methode und Sie eine Erweiterungsmethode mit derselben Signatur haben, bindet der Compiler immer an diese Instanzmethode. Wenn der Compiler auf einen Methodenaufruf stößt, sucht er zunächst nach einer passenden Methode unter den Instanzmethoden dieses Typs. Wenn keine passende Methode gefunden wird, sucht der Compiler nach allen für den Typ definierten Erweiterungsmethoden und bindet an die erste gefundene Erweiterungsmethode. Das folgende Beispiel zeigt, wie der Compiler bestimmt, an welche Erweiterungsmethode oder Instanzmethode gebunden werden soll.

Beispiel

Das folgende Beispiel zeigt, wie der C#-Compiler bestimmt, ob a aufgerufen werden soll Methode Die Regeln, die beim Binden an eine Instanzmethode oder eine Erweiterungsmethode für einen Typ befolgt werden müssen. Statische Klasse Extensions enthält Erweiterungsmethoden, die für jeden Typ definiert sind, der IMyInterface implementiert. Die Klassen A, B und C implementieren alle diese Schnittstelle. Die Erweiterungsmethode

MethodB wird nie aufgerufen, da ihr Name und ihre Signatur genau mit den Methoden übereinstimmen, die bereits von diesen Klassen implementiert wurden.

Wenn der Compiler keine Instanzmethode mit einer passenden Signatur finden kann, bindet er an die passende Erweiterungsmethode (sofern eine solche Methode vorhanden ist).

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)!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn