Rozšíření metody (Příručka programování C#)
Rozšiřující metody umožňují "Přidat" metody existující typy bez vytvoření nového typu odvozené, kompilací nebo jiné úpravy původního typu.Zvláštní druh statické metody jsou metody rozšíření, ale jako by byly rozšířený typ instance metody jsou volány.Pro klientský kód napsaný v jazyce C# a Visual Basic je žádné zjevné rozdíl mezi rozšiřující metody a metody, které skutečně jsou definovány v typu volání.
Nejběžnější způsoby rozšíření jsou LINQ standardních operátorů pro dotazování, které funkce dotazu přidat existující System.Collections.IEnumerable a System.Collections.Generic.IEnumerable<T> typy. Použití standardních operátorů pro dotazování, nejprve je uvedly do oboru s using System.Linq směrnice.Klepněte na libovolný typ, který implementuje IEnumerable<T> , jako má instance metody GroupBy, OrderBy, Average, atd.Uvidíte tyto další metody v technologii IntelliSense dokončování při psaní "tečka" po instanci IEnumerable<T> zadejte jako List<T> nebo Array.
Následující příklad ukazuje, jak volat operátor standardního dotazu OrderBy metoda na pole celých čísel.Výraz v závorkách je lambda výraz.Mnoho standardních operátorů pro dotazování trvat lambda výrazy jako parametry, ale není požadavek pro rozšiřující metody.Další informace naleznete v tématu Lambda výrazy (Příručka programování 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
Rozšiřující metody definovány jako statické metody, ale jsou volány pomocí syntaxi metody instance.Jejich první parametr určuje, jaký typ metoda pracuje a předchází parametru této modifikátor.Rozšiřující metody jsou pouze v rozsahu při explicitně importovat obor názvů do zdrojového kódu se using směrnice.
Následující příklad ukazuje definované pro rozšiřující metodu System.String třídy.Poznámka: je definována uvnitř-vnořené, obecný statické třídy:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
WordCount Rozšiřující metoda může být dovezeno na obor s tímto using směrnice:
using ExtensionMethods;
A může být volána z aplikace pomocí této syntaxe:
string s = "Hello Extension Methods";
int i = s.WordCount();
V kódu vyvolat metodu rozšíření s syntaxi metody instance.Nicméně intermediate language (IL) generovaný kompilátorem přeloží kódu volání statické metody.Proto se zásadou zapouzdření není skutečně porušovány.Rozšiřující metody ve skutečnosti nemá přístup k soukromé proměnné typu jejich rozšíření.
Další informace naleznete v tématu Jak: implementovat a zavolejte metodu vlastní rozšíření (Příručka programování C#).
Obecně je bude pravděpodobně být volání metody rozšíření mnohem častěji než provádění vlastní.Pomocí syntaxe instance metody jsou volány metody rozšíření žádné speciální znalosti je povinna použít z kódu klienta.Povolit rozšíření metod pro konkrétní typ, stačí přidat using směrnice pro obor názvů, ve kterém jsou definovány metody.Použití standardních operátorů pro dotazování, například přidat tento using směrnice kódu:
using System.Linq;
(Budete také muset přidat odkaz na System.Core.dll.) Zjistíte, že standard query operators nyní zobrazí IntelliSense jako další metody pro většinu IEnumerable<T> typy.
[!POZNÁMKA]
Ačkoli standard query operators nezobrazí v technologii IntelliSense pro String, jsou stále k dispozici.
Rozšíření metody vazby v době kompilace
Rozšiřující metody můžete rozšířit třídy nebo rozhraní, ale nikoli je přepsat.Rozšíření metody se stejným názvem a podpis jako rozhraní nebo metodu třídy bude nikdy volána.V době kompilace rozšiřující metody mají vždy nižší prioritu než instance metody definované v samotném typu.Jinými slovy, pokud typ má metodu pojmenovanou Process(int i)a mít rozšiřující metoda se stejnou signaturou, kompilátor vždy svázat metodu instance.Když kompilátor narazí na vyvolání metody, nejprve hledá shodu na typ metody instance.Pokud je nalezena žádná shoda, bude hledat rozšiřujících metod, které jsou definovány pro typ a svázat první rozšiřující metodu, kterou najde.Následující příklad ukazuje, jak kompilátor Určuje, které rozšiřující metoda nebo metoda instance svázat.
Příklad
Následující příklad ukazuje pravidla kompilátor jazyka C#, které se řídí při určování, zda metoda instance typu nebo rozšiřující metodu bind volání metody.Statické třídy Extensions obsahuje rozšiřující metody definovány pro libovolný typ, který implementuje IMyInterface.Třídy A, B, a C všechny implementovat rozhraní.
MethodB Rozšiřující metoda se nazývá nikdy, protože jeho jméno a podpis přesně shodovat metody již implementované třídy.
Když kompilátor nemůže najít odpovídající podpis metody instance, vytvoří vazbu odpovídající metody rozšíření pokud existuje.
// 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()
*/
Obecné pokyny
Obecně doporučujeme implementovat metody rozšíření zřídka a pouze když je nutné.Kdykoli je to možné, klientský kód, který musí rozšířit existující typ by měl provést vytvořením nového typu odvozeného z existujícího typu.Další informace naleznete v tématu Dědičnost (Příručka programování C#).
Rozšíření typu jejíž zdrojový kód nelze změnit pomocí rozšiřující metodu, spustíte riziko, že způsobí změnu v provádění typu vaší rozšiřující metoda přerušit.
Pokud implementujete rozšiřující metody pro daný typ, nezapomeňte followingpoints:
Rozšiřující metoda bude nikdy volána, pokud má stejnou signaturu jako metoda definována v typu.
Rozšiřující metody jsou uvedeny do oboru názvů na úrovni.Například, pokud máte více statických tříd, které obsahují rozšíření metody v jeden obor názvů s názvem Extensions, se budou všechny vnášet obor using Extensions; směrnice.
Pokud implementátorovi knihovny tříd, byste neměli používat rozšíření metody se zvyšující číslo verze sestavení.Pokud chcete přidat významné funkce knihovny, pro který vlastní zdrojový kód, postupujte podle standardní pokyny pro správu verzí sestavení rozhraní.NET Framework.Další informace naleznete v tématu Správa verzí sestavení.
Viz také
Referenční dokumentace
Lambda výrazy (Příručka programování C#)
Koncepty
Přehled operátorů standardní dotaz
Další zdroje
Pravidla převodu Instance parametry a jejich dopad
metody rozšíření spolupráce mezi jazyky