Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A C# 14-től kezdve a legfelső szintű, nemgenerikus static class deklarációk blokkokkal deklarálhatják extension a bővítménytagokat. A bővítménytagok metódusok vagy tulajdonságok, és példánynak vagy statikus tagoknak tűnhetnek. A C# korábbi verziói úgy teszik lehetővé a bővítménymetódusokat , hogy módosítóként hozzáadják this a legfelső szintű, nemgenerikus statikus osztályban deklarált statikus metódus első paraméteréhez.
A C# nyelv referenciadokumentuma a C# nyelv legújabb kiadású verzióját ismerteti. Emellett a közelgő nyelvi kiadás nyilvános előzetes verziójú funkcióinak kezdeti dokumentációját is tartalmazza.
A dokumentáció azonosítja azokat a funkciókat, amelyeket először a nyelv utolsó három verziójában vagy az aktuális nyilvános előzetes verziókban vezetnek be.
Jótanács
Ha meg szeretné tudni, hogy mikor jelent meg először egy funkció a C#-ban, tekintse meg a C# nyelvi verzióelőzményeiről szóló cikket.
A extension blokk megadja a bővítménytagok típusát és fogadóit. A deklarációban extension metódusokat, tulajdonságokat vagy operátorokat deklarálhat. Az alábbi példa egyetlen bővítményblokkot deklarál, amely egy példánykiterjesztési metódust, egy példánytulajdonságot és egy statikus operátori metódust határoz meg.
Megjegyzés:
A cikkben szereplő összes példa tartalmazza a tagok XML-megjegyzéseit és a bővítményblokkot. A blokk csomópontja a extension kiterjesztett típust és a fogadó paramétert írja le. A C#-fordító átmásolja ezt a csomópontot a létrehozott tagra a bővítményblokk összes tagja számára. Ezek a példák bemutatják a bővítménytagok XML-dokumentációjának létrehozásának előnyben részesített stílusát.
/// <summary>
/// Contains extension members for numeric sequences.
/// </summary>
public static class NumericSequences
{
/// <summary>
/// Defines extensions for integer sequences.
/// </summary>
/// <param name="sequence">The sequence used as a receiver.</param>
extension(IEnumerable<int> sequence)
{
/// <summary>
/// Adds a scalar value to each element in the sequence.
/// </summary>
/// <param name="operand">The amount to add.</param>
/// <returns>
/// A new sequence where each value contains the updated value.
/// </returns>
public IEnumerable<int> AddValue(int operand)
{
foreach (var item in sequence)
{
yield return item + operand;
}
}
/// <summary>
/// Gets the median value of the sequence.
/// </summary>
/// <remarks>
/// This value is calculated when requested.
/// </remarks>
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]) / 2;
}
else
{
// Odd number of elements: return the middle element
return sortedList[middleIndex];
}
}
}
/// <summary>
/// Concatenates two sequences of integers into a single sequence.
/// </summary>
/// <remarks>The resulting sequence enumerates all elements from <paramref name="left"/> in order,
/// followed by all elements from <paramref name="right"/>. Enumeration is deferred and performed lazily as the
/// returned sequence is iterated.</remarks>
/// <param name="left">The first sequence of integers to concatenate. Cannot be null.</param>
/// <param name="right">The second sequence of integers to concatenate. Cannot be null.</param>
/// <returns>A sequence that contains the elements of the first sequence followed by the
/// elements of the second sequence.</returns>
public static IEnumerable<int> operator +(IEnumerable<int> left, IEnumerable<int> right)
=> left.Concat(right);
}
}
A extension vevőt a következő határozza meg: sequence, amely egy IEnumerable<int>. A fogadó típusa lehet nemgenerikus, nyitott általános vagy zárt általános típus. A név sequence a bővítményben deklarált összes példánytag hatókörében szerepel. A bővítménymetódus és a tulajdonság egyaránt hozzáfér sequence-hoz.
Bármelyik bővítménytagot úgy érheti el, mintha a fogadótípus tagjai lennének:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
var median = numbers.Median;
var combined = numbers + Enumerable.Range(100, 10);
Egyetlen blokkban tetszőleges számú tagot deklarálhat, feltéve, hogy ugyanazzal a fogadóval rendelkeznek. Egyetlen osztályban is deklarálhat annyi bővítményblokkot. A különböző bővítményeknek nem kell azonos típusú vagy nevű fogadót deklarálniuk. A bővítményparaméternek nem kell tartalmaznia a paraméter nevét, ha csak a tagok statikusak:
/// <summary>
/// Provides static extensions for the <see cref="IEnumerable{Int32}"/> type.
/// </summary>
extension(IEnumerable<int>)
{
// Method:
/// <summary>
/// Generates a sequence of integers, starting from a specified value and incrementing by a given amount.
/// </summary>
/// <param name="low">The starting value of the sequence.</param>
/// <param name="count">The number of integers to generate. Must be non-negative.</param>
/// <param name="increment">The value by which to increment each subsequent integer in the sequence.</param>
/// <returns>
/// An enumerable collection of integers, beginning with the specified starting value and containing the
/// specified number of elements, each incremented by the given amount.
/// </returns>
public static IEnumerable<int> Generate(int low, int count, int increment)
{
for (int i = 0; i < count; i++)
yield return low + (i * increment);
}
// Property:
/// <summary>
/// Gets an empty sequence of integers representing the identity element for sequence operations.
/// </summary>
/// <remarks>
/// This property can be used as a neutral starting point when aggregating or composing
/// sequences of integers. The returned sequence is always empty and does not allocate any storage.
/// </remarks>
public static IEnumerable<int> Identity => Enumerable.Empty<int>();
}
Statikus bővítményeket úgy hívhat meg, mintha a fogadótípus statikus tagjai lennének:
var newSequence = IEnumerable<int>.Generate(5, 10, 2);
var identity = IEnumerable<int>.Identity;
Az operátorokat úgy hívhatja meg, mintha felhasználó által definiált operátorok lennének a típuson.
Fontos
A bővítmények nem vezetnek be hatókört a tagdeklarációkhoz. Az egy osztályban deklarált összes tagnak egyedi aláírással kell rendelkeznie, még akkor is, ha több bővítményben is. A létrehozott aláírás tartalmazza a fogadó típusának nevét a statikus tagoknál, valamint a bővítménypéldány-tagok fogadó paraméterét.
Az alábbi példa egy bővítménymetódust mutat be a this módosító használatával:
public static class NumericSequenceExtensionMethods
{
public static IEnumerable<int> AddValue(this IEnumerable<int> sequence, int operand)
{
foreach (var item in sequence)
yield return item + operand;
}
}
A metódust AddValue bármely más metódusból úgy hívhatja meg, mintha az a IEnumerable<int> felület tagja lenne:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
A kiterjesztési módszerek mindkét formája ugyanazt a köztes nyelvet (IL) hozza létre. A hívók nem tudnak különbséget tenni közöttük. Sőt, a meglévő bővítési metódusokat átalakíthatja az új tagszintaxissá törés nélküli módosítás nélkül. A formátumok bináris és forráskompatibilisek.
Általános bővítményblokkok
Ha megadja a bővítményblokkban deklarált bővítménytag típusparamétereit, az attól függ, hogy hol van szüksége a típusparaméterre:
- Adja hozzá a típusparamétert a
extensiondeklarációhoz, ha a típusparamétert a fogadóban használja. - Adja hozzá a típusparamétert a tagdeklarációhoz, ha a típus eltér a fogadóban megadott típusparamétertől.
- Nem adhatja meg ugyanazt a típusparamétert mindkét helyen.
Az alábbi példa egy bővítményblokkot IEnumerable<T> mutat be, amelyben a bővítmény két tagja egy második típusparamétert igényel:
/// <summary>
/// Contains generic extension members for sequences.
/// </summary>
public static class GenericExtensions
{
/// <summary>
/// Defines extensions for generic sequences.
/// </summary>
/// <typeparam name="TReceiver">The type of elements in the receiver sequence.</typeparam>
/// <param name="source">The sequence used as a receiver.</param>
extension<TReceiver>(IEnumerable<TReceiver> source)
{
/// <summary>
/// Returns a sequence containing a specified number of elements from the source, starting at a given index.
/// </summary>
/// <param name="start">The zero-based index at which to begin retrieving elements. Must be greater than or equal to 0.</param>
/// <param name="count">The number of elements to return. Must be greater than or equal to 0.</param>
/// <returns>
/// An <see cref="IEnumerable{TReceiver}"/> that contains up to <paramref name="count"/> elements from the
/// source sequence, starting at the element at position <paramref name="start"/>. If <paramref name="start"/>
/// is greater than the number of elements in the source, an empty sequence is returned.
/// </returns>
public IEnumerable<TReceiver> Spread(int start, int count)
=> source.Skip(start).Take(count);
/// <summary>
/// Returns a sequence that contains the elements of the original sequence followed by the elements of a
/// specified sequence, each transformed by a converter function.
/// </summary>
/// <remarks>
/// Enumeration of the returned sequence will not start until the sequence is iterated.
/// The converter function is applied to each element of the appended sequence as it is enumerated.
/// </remarks>
/// <typeparam name="TArg">The type of the elements in the sequence to append.</typeparam>
/// <param name="second">The sequence whose elements are to be appended after being converted. Cannot be null.</param>
/// <param name="Converter">A function to convert each element of the appended sequence to the result type. Cannot be null.</param>
/// <returns>
/// An IEnumerable<TReceiver> that contains the elements of the original sequence followed by the converted
/// elements of the specified sequence.
/// </returns>
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);
}
}
/// <summary>
/// Returns a sequence that consists of the elements of the specified collection, transformed by the provided
/// converter, followed by the elements of the current sequence.
/// </summary>
/// <remarks>
/// Enumeration of the returned sequence will not start until the sequence is iterated.
/// Both the input collection and the converter function must not be null; otherwise, an exception will be
/// thrown at enumeration time.
/// </remarks>
/// <typeparam name="TArg">The type of the elements in the collection to prepend.</typeparam>
/// <param name="second">The collection whose elements are to be transformed and prepended to the current sequence. Cannot be null.</param>
/// <param name="converter">A function to convert each element of the prepended collection to the target type. Cannot be null.</param>
/// <returns>
/// An IEnumerable<TReceiver> that contains the converted elements of the specified collection followed by the
/// elements of the current sequence.
/// </returns>
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;
}
}
/// <summary>
/// Gets an empty sequence of the receiver's element type.
/// </summary>
/// <remarks>
/// This property can be used as a neutral starting point when aggregating or composing
/// sequences of the receiver's element type. The returned sequence is always empty and does not allocate any storage.
/// </remarks>
public static IEnumerable<TReceiver> Identity => Enumerable.Empty<TReceiver>();
}
}
A tagok Append , és Prepend adja meg az átalakításhoz szükséges további típusparamétert. Egyik tag sem ismételje meg a fogadó típusparaméterét.
Az egyenértékű bővítménymetódus-deklarációk bemutatják, hogyan vannak kódolva ezek a típusparaméterek:
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;
}
}
}
Lásd még
C# nyelvspecifikáció
További információkért lásd a C# nyelvi specifikációját. A nyelvi specifikáció a C#-szintaxis és -használat végleges forrása.