Udostępnij za pośrednictwem


Rozszerzenie metody (Podręcznik programowania C#)

Rozszerzenie metody pozwalają na "Dodaj" metody do istniejących typów bez tworzenia nowego typu pochodnego, ponownej kompilacji lub w przeciwnym razie modyfikowania oryginalnego typu.Rozszerzenie metody są specjalnym rodzajem metoda statyczna, ale są one nazywane tak, jakby były metody instancji na typ rozszerzony.Kod klienta, napisane w języku C# i Visual Basic, nie wynika różnią się między wywołując metodę rozszerzenia i metody, które faktycznie są zdefiniowane w polu Typ.

Najczęściej rozszerzenie metody są LINQ operatory standardowej kwerendy, które możliwości kwerendy do istniejącego System.Collections.IEnumerable i System.Collections.Generic.IEnumerable<T> typów. Aby użyć operatorów standardowej kwerendy, najpierw dostosowania ich do zakresu o using System.Linq dyrektywy.Następnie dowolnego typu, który implementuje IEnumerable<T> wydaje się, że metody instancji, takie jak GroupBy, OrderBy, Averagei tak dalej.Można zobaczyć te dodatkowe metody w instrukcji IntelliSense po wpisaniu "dot" po wystąpienie IEnumerable<T> wpisz taką jak List<T> lub Array.

Poniższy przykład pokazuje, jak wywołać operatora standardowej kwerendy OrderBy metody na tablica wartości całkowitych.Wyrażenie w nawiasach jest wyrażenie lambda.Wielu operatorów standardowej kwerendy podjąć wyrażenia lambda jako parametry, ale nie jest to wymagane dla metody rozszerzenia.Aby uzyskać więcej informacji, zobacz Wyrażenia lambda (Podręcznik programowania 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

Metody rozszerzenia są definiowane jako metody statyczne, ale są wywoływane przy użyciu składni metody wystąpienia.Ich pierwszy parametr określa, jakiego typu metoda działa na, a parametr jest poprzedzony przez to modyfikator.Rozszerzenie metody są wyłącznie w zakresie, po zaimportowaniu jawnie obszaru nazw do kodu źródłowego, z using dyrektywy.

W poniższym przykładzie przedstawiono metodę rozszerzenia zdefiniowane dla System.String klasy.Należy zauważyć, że zdefiniowano wewnątrz zagnieżdżone, nierodzajową klasy statycznej:

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

WordCount Metoda rozszerzenia mogą być przywożone na zakres z tym using dyrektywę:

using ExtensionMethods;

A może być wywołana z aplikacji przy użyciu następującej składni:

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

W kodzie wywołać metodę rozszerzenia z Składnia metody wystąpienia.Jednak intermediate language (IL), generowanych przez kompilator przetwarza swój kod na wywołanie metody statycznej.W związku z tym zasady hermetyzacja jest nie tak naprawdę naruszane.W rzeczywistości rozszerzenie metody Brak dostępu do prywatnych zmiennych w polu Typ, który jest kolejnym krokiem.

Aby uzyskać więcej informacji, zobacz Jak: wdrożenia i wywołać metodę rozszerzenia niestandardowe (Podręcznik programowania C#).

Ogólnie rzecz biorąc użytkownik prawdopodobnie skontaktuje się rozszerzenie metody częściej niż realizacji własnych.Ponieważ rozszerzenie metody są wywoływane przy użyciu składni metody wystąpienia, żadna specjalistyczna wiedza jest zobowiązana do korzystania z nich z kodu klient.Aby włączyć rozszerzenie metody dla określonego typu, wystarczy dodać using w dyrektywie dla obszaru nazw, w której są zdefiniowane metody.Na przykład, aby używać operatorów standardowej kwerendy, należy dodać to using w dyrektywie do kodu:

using System.Linq;

(Może również trzeba dodać odwołanie do System.Core.dll.) Można zauważyć, że operatory standardowej kwerendy teraz wyświetlone w technologii IntelliSense jako dodatkowe metody dostępne dla większości IEnumerable<T> typów.

[!UWAGA]

Chociaż operatory standardowej kwerendy nie są wyświetlane w technologii IntelliSense dla String, będą nadal dostępne.

Metody rozszerzenia wiązania w czasie kompilacji

Rozszerzenie metody można użyć do rozszerzenia klasy lub interfejsu, ale nie w celu ich pominięcia.Nigdy nie zostanie wywołana metoda rozszerzenia o tej samej nazwie i podpisie jako interfejsu lub metody klasy.W czasie kompilacji rozszerzenie metody zawsze mają niższy priorytet niż zdefiniowane w właściwy typ metody instancji.Innymi słowy, jeśli typ ma metodę wspomniany Process(int i)i masz metodę rozszerzenia o tej samej sygnaturze, kompilator zawsze wiążą się metody instancji.Gdy kompilator napotka wywołania metody, najpierw szuka mecz w metody instancji typu.Jeśli nie zostanie znaleziony, przeszukiwane są na wszelkie metody rozszerzenia, które są zdefiniowane dla danego typu i utwórz powiązanie z pierwszą metodą rozszerzenie, które znajdzie.Poniższy przykład ilustruje, jak kompilator Określa, które metoda rozszerzenia lub metody instancji, aby powiązać.

Przykład

Poniższy przykład ilustruje zasady, że kompilator C# następuje przy podejmowaniu decyzji dotyczącej bind wywołanie metody do metody wystąpienia w typie, a także metodę rozszerzenia.Klasy statycznej Extensions zawiera rozszerzenie metody zdefiniowane dla dowolnego typu, który implementuje IMyInterface.Klasy A, B, i C wszystkie implementują interfejs.

MethodB Nigdy nie nazywa metoda rozszerzenia, ponieważ jego nazwisko i podpis dokładnie odpowiadać metody już implementowane przez klasy.

Kompilator nie może odnaleźć metody instancji przy użyciu podpisu dopasowania, będzie powiązać do pasującego metoda rozszerzenia, jeśli taki istnieje.

// 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()
 */

Ogólne wytyczne

Ogólnie rzecz biorąc, firma Microsoft zaleca implementowanie rozszerzenie metody oszczędnie i tylko jeśli to konieczne.O ile to możliwe, kod klienta, która musi rozszerzyć istniejącego typu powinny się odbywać przez utworzenie nowego typu, pochodzące z istniejącym typem.Aby uzyskać więcej informacji, zobacz Dziedziczenie (Podręcznik programowania C#).

Rozszerzenie typu kod źródłowy, którego nie można zmienić za pomocą metody rozszerzenia, uruchomieniu ryzyko, że zmiana w celu wykonania tego typu spowoduje, że Twój metoda rozszerzenia przerwać.

W przypadku zastosowania metody rozszerzenia dla danego typu, należy pamiętać o followingpoints:

  • Metodę rozszerzenia nigdy nie zostanie wywołana, gdy ma on taką samą sygnaturę jak metoda, która w typie.

  • Rozszerzenie metody są sprowadzane do zakresu na poziomie obszaru nazw.Na przykład, jeśli masz wiele klas statycznych, które zawierają rozszerzenie metody w pojedynczy obszar nazw o nazwie Extensions, zostaną one wszystko doprowadzone do zakresu przez using Extensions; dyrektywy.

Dla biblioteki klas, który zostanie wdrożony nie można używać metody rozszerzenia do uniknięcia, zwiększając tę wartość numer wersji zestawu.Jeśli chcesz dodać funkcjonalność do biblioteki, dla którego posiadasz kod źródłowy, należy wykonać standardowe wytyczne.NET Framework dla wersji zestawu.Aby uzyskać więcej informacji, zobacz Przechowywanie wersji zestawu.

Zobacz też

Informacje

Wyrażenia lambda (Podręcznik programowania C#)

Koncepcje

Podręcznik programowania C#

Omówienie operatory kwerendy standardowe

Inne zasoby

Konwersji na przykład zasady parametry i ich wpływu na

rozszerzenie metody współdziałania między językami

rozszerzenie metody i Porozumienia administracyjnego delegatów

Metoda rozszerzenia wiązania oraz zgłaszanie błędów w