Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Vanaf C# 14 kunnen niet-gegenereerde static class declaraties op het hoogste niveau gebruikmaken van extension blokken om extensieleden te declareren. Extensieleden zijn methoden of eigenschappen en kunnen instanties of statische leden zijn. Eerdere versies van C# maken uitbreidingsmethoden mogelijk door als een wijzigingsfunctie toe te voegen this aan de eerste parameter van een statische methode die is gedeclareerd in een statische klasse op het hoogste niveau.
Het extension blok geeft het type en de ontvanger op voor extensieleden. U kunt methoden, eigenschappen of operators in de extension declaratie declareren. In het volgende voorbeeld wordt één extensieblok declareren dat een instantieextensiemethode, een exemplaareigenschap en een statische operatormethode definieert.
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 static IEnumerable<int> operator +(IEnumerable<int> left, IEnumerable<int> right)
=> left.Concat(right);
}
}
Hiermee extension definieert u de ontvanger: sequence, dat is een IEnumerable<int>. Het type ontvanger kan niet-gegenereerd zijn, een open generic of een gesloten algemeen type. De naam sequence valt onder de reikwijdte van elk instantiëlid dat gedeclareerd is in die extensie. De extensiemethode en de eigenschap hebben beide toegang tot sequence.
Elk van de extensieleden kan worden geopend alsof ze lid zijn van het ontvangertype:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
var median = numbers.Median;
var combined = numbers + Enumerable.Range(100, 10);
U kunt een willekeurig aantal leden in één blok declareren, zolang ze dezelfde ontvanger delen. U kunt ook zoveel extensieblokken in één klasse declareren. Verschillende extensies hoeven niet hetzelfde type of dezelfde naam van de ontvanger te declareren. De extensieparameter hoeft de parameternaam niet op te nemen als de enige leden statisch zijn:
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>();
}
Statische extensies kunnen worden aangeroepen alsof ze statische leden van het ontvangertype zijn:
var newSequence = IEnumerable<int>.Generate(5, 10, 2);
var identity = IEnumerable<int>.Identity;
Operators worden aangeroepen alsof ze door de gebruiker gedefinieerde operators voor het type zijn.
Belangrijk
Een uitbreiding introduceert geen bereik voor liddeclaraties. Alle leden die in één klasse zijn gedeclareerd, zelfs als ze meerdere extensies hebben, moeten unieke handtekeningen hebben. De gegenereerde handtekening bevat het type ontvanger in de naam voor statische leden en de ontvangerparameter voor leden van het extensie-exemplaar.
In het volgende voorbeeld ziet u een extensiemethode met behulp van de this modifier:
public static class NumericSequenceExtensionMethods
{
public static IEnumerable<int> AddValue(this IEnumerable<int> sequence, int operand)
{
foreach (var item in sequence)
yield return item + operand;
}
}
De Add methode kan worden aangeroepen vanuit elke andere methode alsof deze lid is van de IEnumerable<int> interface:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
Beide vormen van extensiemethoden genereren dezelfde tussenliggende taal (IL). Bellers kunnen er geen onderscheid tussen maken. In feite kunt u bestaande extensiemethoden converteren naar de syntaxis van het nieuwe lid zonder een wijziging die fouten veroorzaken. De indelingen zijn zowel binair als broncompatibel.
Algemene extensieblokken
Waar u de typeparameters voor een extensielid opgeeft dat is gedeclareerd in een extensieblok, is afhankelijk van waar die typeparameter is vereist:
- U voegt de typeparameter toe aan de
extensiondeclaratie wanneer de typeparameter wordt gebruikt in de ontvanger. - U voegt de typeparameter toe aan de liddeclaratie wanneer het type verschilt van een typeparameter die is opgegeven op de ontvanger.
- U kunt op beide locaties niet hetzelfde typeparameter opgeven.
In het volgende voorbeeld ziet u een extensieblok voor IEnumerable<T> waarin twee van de extensieleden een tweede typeparameter vereisen.
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;
}
}
}
}
De leden Append en Prepend specificeren de typeparameter extra voor de conversie. Geen van de leden herhaalt de typeparameter voor de ontvanger.
De equivalente uitbreidingsmethodedeclaraties laten zien hoe deze typeparameters worden gecodeerd:
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;
}
}
}
Zie ook
C#-taalspecificatie
Zie de C#-taalspecificatie voor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.