Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Dimulai dengan C# 14, deklarasi nongenerik static class tingkat atas dapat menggunakan extension blok untuk mendeklarasikan anggota ekstensi. Anggota ekstensi adalah metode atau properti dan dapat tampak sebagai instans atau anggota statis. Versi C# sebelumnya mengaktifkan metode ekstensi dengan menambahkan this sebagai pengubah ke parameter pertama metode statis yang dideklarasikan dalam kelas statis nongenerik tingkat atas.
extension Blok menentukan jenis dan penerima untuk anggota ekstensi. Anda dapat mendeklarasikan metode, properti, atau operator di extension dalam deklarasi. Contoh berikut mendeklarasikan satu blok ekstensi yang menentukan metode ekstensi instans, properti instans, dan metode operator statis.
Nota
Semua contoh dalam artikel ini menyertakan komentar XML untuk anggota dan blok ekstensi. Simpul pada extension blok menjelaskan jenis yang diperluas dan parameter penerima. Pengkompilasi C# menyalin simpul ini ke anggota yang dihasilkan untuk semua anggota di blok ekstensi. Contoh-contoh ini menunjukkan gaya pilihan untuk menghasilkan dokumentasi XML untuk anggota ekstensi.
/// <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);
}
}
extension mendefinisikan penerima: sequence, yang merupakan IEnumerable<int>. Jenis penerima bisa nongenerik, generik terbuka, atau jenis generik tertutup. Nama sequence ini berada dalam cakupan di setiap anggota instans yang dideklarasikan dalam ekstensi tersebut. Metode ekstensi dan properti keduanya mengakses sequence.
Anda mengakses salah satu anggota ekstensi seolah-olah mereka adalah anggota jenis penerima:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
var median = numbers.Median;
var combined = numbers + Enumerable.Range(100, 10);
Anda dapat mendeklarasikan sejumlah anggota dalam satu blok, selama mereka berbagi penerima yang sama. Anda juga dapat mendeklarasikan sebanyak mungkin blok ekstensi dalam satu kelas. Ekstensi yang berbeda tidak perlu mendeklarasikan jenis atau nama penerima yang sama. Parameter ekstensi tidak perlu menyertakan nama parameter jika satu-satunya anggota statis:
/// <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>();
}
Anda memanggil ekstensi statis seolah-olah mereka adalah anggota statis dari jenis penerima:
var newSequence = IEnumerable<int>.Generate(5, 10, 2);
var identity = IEnumerable<int>.Identity;
Anda memanggil operator seolah-olah operator tersebut adalah operator yang ditentukan pengguna pada jenis tersebut.
Penting
Ekstensi tidak memperkenalkan cakupan untuk deklarasi anggota. Semua anggota yang dideklarasikan dalam satu kelas, bahkan jika dalam beberapa ekstensi, harus memiliki tanda tangan unik. Tanda tangan yang dihasilkan mencakup jenis penerima dalam namanya untuk anggota statis dan parameter penerima untuk anggota instans ekstensi.
Contoh berikut menunjukkan metode ekstensi menggunakan pengubah this :
public static class NumericSequenceExtensionMethods
{
public static IEnumerable<int> AddValue(this IEnumerable<int> sequence, int operand)
{
foreach (var item in sequence)
yield return item + operand;
}
}
Anda dapat memanggil Add metode dari metode lain seolah-olah itu adalah anggota IEnumerable<int> antarmuka:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);
Kedua bentuk metode ekstensi menghasilkan bahasa perantara (IL) yang sama. Penelepon tidak dapat membuat perbedaan di antara mereka. Sebenarnya, Anda dapat mengonversi metode ekstensi yang ada ke sintaks anggota baru tanpa perubahan yang melanggar. Format-format tersebut kompatibel dengan biner dan sumber.
Blok ekstensi generik
Di mana Anda menentukan parameter jenis untuk anggota ekstensi yang dideklarasikan dalam blok ekstensi bergantung pada di mana Anda memerlukan parameter jenis:
- Tambahkan parameter jenis ke
extensiondeklarasi saat parameter jenis digunakan dalam penerima. - Tambahkan parameter jenis ke deklarasi anggota saat jenis berbeda dari parameter jenis apa pun yang ditentukan pada penerima.
- Anda tidak dapat menentukan parameter jenis yang sama di kedua lokasi.
Contoh berikut menunjukkan blok ekstensi di IEnumerable<T> mana dua anggota ekstensi memerlukan parameter jenis kedua:
/// <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;
}
}
}
}
Append dan Prepend menentukan parameter jenis tambahan untuk konversi. Tidak ada anggota yang mengulangi parameter tipe untuk penerima.
Deklarasi metode ekstensi yang setara menunjukkan bagaimana parameter jenis tersebut dikodekan:
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;
}
}
}
Lihat juga
Spesifikasi bahasa C#
Untuk informasi selengkapnya, lihat Spesifikasi Bahasa C#. Spesifikasi bahasa adalah sumber definitif untuk sintaks dan penggunaan C#.