Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Počínaje jazykem C# 14 mohou negenerické, nejvyšší úrovně static class
deklarace za použití extension
kontejnerů deklarovat členy rozšíření. Členy rozšíření jsou metody nebo vlastnosti a mohou se zdát, že jde o instance nebo statické členy. Starší verze jazyka C# umožňují rozšiřující metody přidáním this
jako modifikátoru do prvního parametru statické metody deklarované v negenerické statické třídě nejvyšší úrovně.
Blok extension
určuje typ a přijímač pro členy rozšíření. Můžete deklarovat metody a vlastnosti uvnitř extension
deklarace. Následující příklad deklaruje jeden blok rozšíření, který definuje metodu rozšíření instance a vlastnost instance.
public static class NumericSequences
{
extension(IEnumerable<int> sequence)
{
public IEnumerable<int> AddValue(int operand)
{
foreach (var item in sequence)
{
yield return item + operand;
}
}
public int Median
{
get
{
var sortedList = sequence.OrderBy(n => n).ToList();
int count = sortedList.Count;
int middleIndex = count / 2;
if (count % 2 == 0)
{
// Even number of elements: average the two middle elements
return (sortedList[middleIndex - 1] + sortedList[middleIndex]);
}
else
{
// Odd number of elements: return the middle element
return sortedList[middleIndex];
}
}
}
public int this[int index] => sequence.Skip(index).First();
}
}
extension
definuje přijímač: sequence
, což je IEnumerable<int>
. Typ přijímače může být negenerický, otevřený obecný nebo uzavřený obecný typ. Název sequence
je dostupný ve všech deklarovaných členech instance v rámci tohoto rozšíření. Metoda rozšíření i vlastnost obě přistupují k sequence
.
K libovolnému členu rozšíření lze přistupovat, jako by se jednalo o členy typu příjemce:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
var median = numbers.Median;
Můžete deklarovat libovolný počet členů v jednom kontejneru, pokud sdílejí stejný příjemce. Můžete deklarovat tolik rozšiřujících bloků, kolik chcete, v jedné třídě. Různá rozšíření nemusí deklarovat stejný typ nebo název příjemce. Parametr rozšíření nemusí obsahovat název parametru, pokud jsou pouze statické členy:
extension(IEnumerable<int>)
{
// Method:
public static IEnumerable<int> Generate(int low, int count, int increment)
{
for (int i = 0; i < count; i++)
yield return low + (i * increment);
}
// Property:
public static IEnumerable<int> Identity => Enumerable.Empty<int>();
}
Statická rozšíření se dají volat, jako by se jedná o statické členy typu příjemce:
var newSequence = IEnumerable<int>.Generate(5, 10, 2);
var identity = IEnumerable<int>.Identity;
Důležité
Rozšíření nezavádí obor pro deklarace členů. Všichni členové deklarovaní v jedné třídě, i když ve více rozšířeních, musí mít jedinečné podpisy. Vygenerovaný podpis obsahuje typ příjemce v jeho názvu pro statické členy a parametr příjemce pro členy instance rozšíření.
Následující příklad ukazuje rozšiřující metodu this
používající modifikátor:
public static class NumericSequenceExtensionMethods
{
public static IEnumerable<int> AddValue(this IEnumerable<int> sequence, int operand)
{
foreach (var item in sequence)
yield return item + operand;
}
}
Metodu Add
lze volat z jakékoli jiné metody, jako by byla členem IEnumerable<int>
rozhraní:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
Obě formy rozšiřujících metod generují stejný zprostředkující jazyk (IL). Volající nemůžou rozlišovat mezi nimi. Ve skutečnosti můžete stávající metody rozšíření převést na novou syntaxi člena bez zásadní změny. Formáty jsou kompatibilní jak ve formátu binárním, tak zdrojovém.
Obecné bloky rozšíření
Kde zadáte parametry typu člena rozšíření deklarovaného v bloku rozšíření, závisí na tom, kde je tento parametr typu povinný:
- Parametr typu přidáte do
extension
deklarace při použití parametru typu v přijímači. - Parametr typu přidáte do deklarace členu, pokud se typ liší od jakéhokoli parametru typu zadaného v přijímači.
- Na obou místech nemůžete zadat stejný typ parametru.
Následující příklad ukazuje blok rozšíření pro IEnumerable<T>
, ve kterém dva členové rozšíření vyžadují druhý typový parametr.
public static class GenericExtensions
{
extension<TReceiver>(IEnumerable<TReceiver> source)
{
public IEnumerable<TReceiver> Spread(int start, int count)
=> source.Skip(start).Take(count);
public IEnumerable<TReceiver> Append<TArg>(IEnumerable<TArg> second, Func<TArg, TReceiver> Converter)
{
foreach(TReceiver item in source)
{
yield return item;
}
foreach (TArg item in second)
{
yield return Converter(item);
}
}
public IEnumerable<TReceiver> Prepend<TArg>(IEnumerable<TArg> second, Func<TArg, TReceiver> Converter)
{
foreach (TArg item in second)
{
yield return Converter(item);
}
foreach (TReceiver item in source)
{
yield return item;
}
}
}
}
Členové Append
a Prepend
určují dodatečný parametr typu pro převod. Žádný člen neopakuje parametr typu příjemce.
Deklarace ekvivalentní metody rozšíření ukazují, jak jsou tyto parametry typu kódovány:
public static class GenericExtensions
{
public static IEnumerable<T> Spread<T>(this IEnumerable<T> source, int start, int count)
=> source.Skip(start).Take(count);
public static IEnumerable<T1> Append<T1, T2>(this IEnumerable<T1> source, IEnumerable<T2> second, Func<T2, T1> Converter)
{
foreach (T1 item in source)
{
yield return item;
}
foreach (T2 item in second)
{
yield return Converter(item);
}
}
public static IEnumerable<T1> Prepend<T1, T2>(this IEnumerable<T1> source, IEnumerable<T2> second, Func<T2, T1> Converter)
{
foreach (T2 item in second)
{
yield return Converter(item);
}
foreach (T1 item in source)
{
yield return item;
}
}
}
Viz také
Specifikace jazyka C#
Další informace najdete ve specifikaci jazyka C#. Specifikace jazyka je konečným zdrojem syntaxe a použití jazyka C#.