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.
Semua metode berbasis LINQ mengikuti salah satu dari dua pola serupa. Mereka mengambil urutan yang dapat dihitung. Mereka mengembalikan urutan yang berbeda atau satu nilai tunggal. Konsistensi bentuk memungkinkan Anda memperluas LINQ dengan menulis metode dengan bentuk yang sama. Bahkan, pustaka .NET mendapatkan metode baru dalam banyak rilis .NET sejak LINQ pertama kali diperkenalkan. Dalam artikel ini, Anda melihat contoh perluasan LINQ dengan menulis metode Anda sendiri yang mengikuti pola yang sama.
Menambahkan metode kustom untuk kueri LINQ
Perluas set metode yang Anda gunakan untuk kueri LINQ dengan menambahkan metode ekstensi ke IEnumerable<T> antarmuka. Misalnya, selain operasi rata-rata standar atau maksimum, Anda membuat metode agregat kustom untuk menghitung satu nilai dari urutan nilai. Anda juga membuat metode yang berfungsi sebagai filter kustom atau transformasi data tertentu untuk urutan nilai dan mengembalikan urutan baru. Contoh metode tersebut adalah Distinct, , Skipdan Reverse.
Saat memperluas IEnumerable<T> antarmuka, Anda dapat menerapkan metode kustom ke koleksi yang dapat dijumlahkan. Untuk informasi selengkapnya, lihat Anggota ekstensi.
Metode agregat menghitung satu nilai dari sekumpulan nilai. LINQ menyediakan beberapa metode agregat, termasuk Average, , Mindan Max. Buat metode agregat Anda sendiri dengan menambahkan metode ekstensi ke IEnumerable<T> antarmuka.
Mulai dari C# 14, Anda dapat mendeklarasikan blok ekstensi untuk berisi beberapa anggota ekstensi. Deklarasikan blok ekstensi dengan kata kunci extension diikuti oleh parameter penerima dalam tanda kurung. Contoh kode berikut menunjukkan cara membuat metode ekstensi yang disebut Median dalam blok ekstensi. Metode ini menghitung median untuk urutan jumlah jenis double.
extension(IEnumerable<double>? source)
{
public double Median()
{
if (source is null || !source.Any())
{
throw new InvalidOperationException("Cannot compute median for a null or empty set.");
}
var sortedList =
source.OrderBy(number => number).ToList();
int itemIndex = sortedList.Count / 2;
if (sortedList.Count % 2 == 0)
{
// Even number of items.
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Odd number of items.
return sortedList[itemIndex];
}
}
}
Anda juga dapat menambahkan pengubah this ke metode statis untuk mendeklarasikan metode ekstensi. Kode berikut menunjukkan metode ekstensi yang setara Median :
public static class EnumerableExtension
{
public static double Median(this IEnumerable<double>? source)
{
if (source is null || !source.Any())
{
throw new InvalidOperationException("Cannot compute median for a null or empty set.");
}
var sortedList =
source.OrderBy(number => number).ToList();
int itemIndex = sortedList.Count / 2;
if (sortedList.Count % 2 == 0)
{
// Even number of items.
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Odd number of items.
return sortedList[itemIndex];
}
}
}
Panggil salah satu metode ekstensi untuk koleksi yang dapat dijumlahkan dengan cara yang sama seperti Anda memanggil metode agregat lain dari IEnumerable<T> antarmuka.
Contoh kode berikut menunjukkan cara menggunakan Median metode untuk array jenis double.
double[] numbers = [1.9, 2, 8, 4, 5.7, 6, 7.2, 0];
var query = numbers.Median();
Console.WriteLine($"double: Median = {query}");
// This code produces the following output:
// double: Median = 4.85
Overload metode agregat Anda agar dapat menerima urutan dari berbagai jenis. Pendekatan standar adalah membuat kelebihan beban untuk setiap jenis. Pendekatan lain adalah membuat kelebihan beban yang mengambil jenis generik dan mengonversinya ke jenis tertentu dengan menggunakan delegasi. Anda juga dapat menggabungkan kedua pendekatan.
Buat kelebihan beban tertentu untuk setiap jenis yang ingin Anda dukung. Contoh kode berikut menunjukkan overloading dari metode Median untuk tipe int.
// int overload
public static double Median(this IEnumerable<int> source) =>
(from number in source select (double)number).Median();
Anda sekarang dapat memanggil Median overload untuk tipe integer dan double, seperti ditunjukkan dalam kode berikut:
double[] numbers1 = [1.9, 2, 8, 4, 5.7, 6, 7.2, 0];
var query1 = numbers1.Median();
Console.WriteLine($"double: Median = {query1}");
int[] numbers2 = [1, 2, 3, 4, 5];
var query2 = numbers2.Median();
Console.WriteLine($"int: Median = {query2}");
// This code produces the following output:
// double: Median = 4.85
// int: Median = 3
Anda juga dapat membuat overload yang menerima urutan objek generik. Kelebihan beban ini mengambil delegasi sebagai parameter dan menggunakannya untuk mengonversi urutan objek dari jenis generik ke jenis tertentu.
Kode berikut menunjukkan kelebihan beban Median metode yang mengambil Func<T,TResult> delegasi sebagai parameter. Delegasi ini mengambil objek jenis generik T dan mengembalikan objek jenis double.
// generic overload
public static double Median<T>(
this IEnumerable<T> numbers, Func<T, double> selector) =>
(from num in numbers select selector(num)).Median();
Anda sekarang dapat memanggil Median metode untuk urutan objek dari jenis apa pun. Jika jenis tidak memiliki kelebihan beban metodenya sendiri, berikan parameter delegasi. Di C#, Anda dapat menggunakan ekspresi lambda untuk tujuan ini. Selain itu, hanya di Visual Basic, jika Anda menggunakan Aggregate klausa atau Group By alih-alih panggilan metode, Anda dapat meneruskan nilai atau ekspresi apa pun yang ada dalam cakupan klausa ini.
Contoh kode berikut menunjukkan cara memanggil Median metode untuk array bilangan bulat dan array string. Untuk string, median untuk panjang string dalam array dihitung. Contoh menunjukkan cara meneruskan Func<T,TResult> parameter delegasi ke Median metode untuk setiap kasus.
int[] numbers3 = [1, 2, 3, 4, 5];
/*
You can use the num => num lambda expression as a parameter for the Median method
so that the compiler will implicitly convert its value to double.
If there is no implicit conversion, the compiler will display an error message.
*/
var query3 = numbers3.Median(num => num);
Console.WriteLine($"int: Median = {query3}");
string[] numbers4 = ["one", "two", "three", "four", "five"];
// With the generic overload, you can also use numeric properties of objects.
var query4 = numbers4.Median(str => str.Length);
Console.WriteLine($"string: Median = {query4}");
// This code produces the following output:
// int: Median = 3
// string: Median = 4
IEnumerable<T> Perluas antarmuka dengan metode kueri kustom yang mengembalikan urutan nilai. Dalam hal ini, metode harus mengembalikan kumpulan jenis IEnumerable<T>. Metode tersebut dapat digunakan untuk menerapkan filter atau transformasi data ke urutan nilai.
Contoh berikut menunjukkan cara membuat metode ekstensi bernama AlternateElements yang mengembalikan setiap elemen lain dalam koleksi, dimulai dari elemen pertama.
// Extension method for the IEnumerable<T> interface.
// The method returns every other element of a sequence.
public static IEnumerable<T> AlternateElements<T>(this IEnumerable<T> source)
{
int index = 0;
foreach (T element in source)
{
if (index % 2 == 0)
{
yield return element;
}
index++;
}
}
Panggil metode ekstensi ini untuk koleksi yang dapat dijumlahkan seperti yang akan Anda panggil metode lain dari IEnumerable<T> antarmuka, seperti yang ditunjukkan dalam kode berikut:
string[] strings = ["a", "b", "c", "d", "e"];
var query5 = strings.AlternateElements();
foreach (var element in query5)
{
Console.WriteLine(element);
}
// This code produces the following output:
// a
// c
// e
Setiap contoh yang ditampilkan dalam artikel ini memiliki penerima yang berbeda. Itu berarti Anda harus mendeklarasikan setiap metode dalam blok ekstensi berbeda yang menentukan penerima unik. Contoh kode berikut menunjukkan satu kelas statis dengan tiga blok ekstensi yang berbeda, yang masing-masing berisi salah satu metode yang ditentukan dalam artikel ini:
public static class EnumerableExtension
{
extension(IEnumerable<double>? source)
{
public double Median()
{
if (source is null || !source.Any())
{
throw new InvalidOperationException("Cannot compute median for a null or empty set.");
}
var sortedList =
source.OrderBy(number => number).ToList();
int itemIndex = sortedList.Count / 2;
if (sortedList.Count % 2 == 0)
{
// Even number of items.
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Odd number of items.
return sortedList[itemIndex];
}
}
}
extension(IEnumerable<int> source)
{
public double Median() =>
(from number in source select (double)number).Median();
}
extension<T>(IEnumerable<T> source)
{
public double Median(Func<T, double> selector) =>
(from num in source select selector(num)).Median();
public IEnumerable<T> AlternateElements()
{
int index = 0;
foreach (T element in source)
{
if (index % 2 == 0)
{
yield return element;
}
index++;
}
}
}
}
Blok ekstensi akhir mendeklarasikan blok ekstensi generik. Parameter tipe untuk penerima dideklarasikan secara langsung pada extension.
Contoh sebelumnya mendeklarasikan satu anggota ekstensi di setiap blok ekstensi. Dalam kebanyakan kasus, Anda membuat beberapa anggota ekstensi untuk penerima yang sama. Dalam kasus tersebut, nyatakan ekstensi untuk anggota tersebut dalam satu blok ekstensi.