Jenis tuple (referensi C#)
Tersedia dalam C# 7.0 dan yang lebih baru, fitur tuple menyediakan sintaks ringkas untuk mengelompokkan beberapa elemen data dalam struktur data yang ringan. Contoh berikut menunjukkan cara Anda mendeklarasikan variabel tuple, menginisialisasinya, dan mengakses anggota datanya:
(double, int) t1 = (4.5, 3);
Console.WriteLine($"Tuple with elements {t1.Item1} and {t1.Item2}.");
// Output:
// Tuple with elements 4.5 and 3.
(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.
Seperti yang ditunjukkan contoh sebelumnya, untuk menentukan jenis tuple, Anda menentukan jenis semua anggota datanya dan, secara opsional, nama bidang. Anda tidak dapat menentukan metode dalam jenis tuple, tetapi Anda dapat menggunakan metode yang disediakan oleh .NET, seperti yang ditunjukkan contoh berikut:
(double, int) t = (4.5, 3);
Console.WriteLine(t.ToString());
Console.WriteLine($"Hash code of {t} is {t.GetHashCode()}.");
// Output:
// (4.5, 3)
// Hash code of (4.5, 3) is 718460086.
Dimulai dengan C# 7.3, jenis tuple mendukung operator kesetaraan== dan !=. Untuk informasi selengkapnya, lihat bagian Kesetaraan tuple di bawah ini.
Jenis tuple adalah jenis nilai; elemen tuple adalah bidang publik. Itu membuat tuple jenis nilai yang dapat diubah.
Catatan
Fitur tuple memerlukan jenis System.ValueTuple dan jenis generik terkait (misalnya, System.ValueTuple<T1,T2>), yang tersedia di .NET Core dan .NET Framework 4.7 dan yang lebih baru. Untuk menggunakan tuple dalam proyek yang menargetkan .NET Framework 4.6.2 atau yang lebih lama, tambahkan paket System.ValueTuple NuGet ke proyek.
Anda dapat menentukan tuple dengan sejumlah besar elemen yang berubah-ubah:
var t =
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26);
Console.WriteLine(t.Item26); // output: 26
Kasus penggunaan tuple
Salah satu kasus penggunaan tuple yang paling umum adalah sebagai jenis pengembalian metode. Artinya, daripada menentukan out parameter metode, Anda dapat mengelompokkan metode menghasilkan jenis pengembalian tuple, seperti yang ditunjukkan contoh berikut:
var xs = new[] { 4, 7, 9 };
var limits = FindMinMax(xs);
Console.WriteLine($"Limits of [{string.Join(" ", xs)}] are {limits.min} and {limits.max}");
// Output:
// Limits of [4 7 9] are 4 and 9
var ys = new[] { -9, 0, 67, 100 };
var (minimum, maximum) = FindMinMax(ys);
Console.WriteLine($"Limits of [{string.Join(" ", ys)}] are {minimum} and {maximum}");
// Output:
// Limits of [-9 0 67 100] are -9 and 100
(int min, int max) FindMinMax(int[] input)
{
if (input is null || input.Length == 0)
{
throw new ArgumentException("Cannot find minimum and maximum of a null or empty array.");
}
var min = int.MaxValue;
var max = int.MinValue;
foreach (var i in input)
{
if (i < min)
{
min = i;
}
if (i > max)
{
max = i;
}
}
return (min, max);
}
Seperti yang ditunjukkan oleh contoh sebelumnya, Anda dapat bekerja dengan instans tuple yang dikembalikan secara langsung atau melakukan dekonstruksi dalam variabel terpisah.
Anda juga dapat menggunakan jenis tuple alih-alih jenis anonim; misalnya, dalam kueri LINQ. Untuk informasi selengkapnya, lihat Memilih antara jenis anonim dan tuple.
Biasanya, Anda menggunakan tuple untuk mengelompokkan elemen data yang terkait secara longgar. Itu biasanya berguna dalam metode utilitas privat dan internal. Dalam kasus API publik, pertimbangkan untuk menentukan kelas atau jenis struktur.
Nama bidang Tuple
Anda dapat secara eksplisit menentukan nama bidang tuple baik dalam ekspresi inisialisasi tuple atau dalam definisi jenis tuple, seperti yang ditunjukkan contoh berikut:
var t = (Sum: 4.5, Count: 3);
Console.WriteLine($"Sum of {t.Count} elements is {t.Sum}.");
(double Sum, int Count) d = (4.5, 3);
Console.WriteLine($"Sum of {d.Count} elements is {d.Sum}.");
Dimulai dengan C # 7.1, jika Anda tidak menentukan nama bidang, itu dapat disimpulkan dari nama variabel yang sesuai dalam ekspresi inisialisasi tuple, seperti yang ditunjukkan contoh berikut:
var sum = 4.5;
var count = 3;
var t = (sum, count);
Console.WriteLine($"Sum of {t.count} elements is {t.sum}.");
Itu dikenal sebagai inisialisasi proyeksi tuple. Nama variabel tidak diproyeksikan ke nama bidang tuple dalam kasus berikut:
- Nama kandidat adalah nama anggota dari jenis tuple, misalnya,
Item3,ToString, atauRest. - Nama kandidat adalah duplikat dari nama bidang tuple lain, baik eksplisit atau implisit.
Dalam kasus tersebut, Anda secara eksplisit menentukan nama bidang atau mengakses bidang dengan nama defaultnya.
Nama default bidang tuple adalah Item1, Item2, Item3 dan sebagainya. Anda selalu dapat menggunakan nama default bidang, bahkan ketika nama bidang ditentukan secara eksplisit atau disimpulkan, seperti yang ditunjukkan contoh berikut:
var a = 1;
var t = (a, b: 2, 3);
Console.WriteLine($"The 1st element is {t.Item1} (same as {t.a}).");
Console.WriteLine($"The 2nd element is {t.Item2} (same as {t.b}).");
Console.WriteLine($"The 3rd element is {t.Item3}.");
// Output:
// The 1st element is 1 (same as 1).
// The 2nd element is 2 (same as 2).
// The 3rd element is 3.
Penugasan tuple dan perbandingan kesetaraan tuple tidak mempertimbangan nama bidang.
Pada waktu kompilasi, kompiler mengganti nama bidang non-default dengan nama default yang sesuai. Akibatnya, nama bidang yang ditentukan atau disimpulkan secara eksplisit tidak tersedia pada waktu berjalan.
Tip
Aktifkan aturan gaya kode .NET IDE0037 untuk mengatur preferensi pada nama bidang tuple yang disimpulkan atau eksplisit.
Penugasan dan dekonstruksi tuple
C# mendukung penugasan antara jenis tuple yang memenuhi kedua kondisi berikut:
- kedua jenis tuple memiliki jumlah elemen yang sama
- untuk setiap posisi tuple, jenis elemen tuple tangan kanan sama dengan atau secara implisit dapat dikonversi ke jenis elemen tuple kiri yang sesuai
Nilai elemen tuple ditetapkan mengikuti urutan elemen tuple. Nama bidang tuple diabaikan dan tidak ditetapkan, seperti yang ditunjukkan contoh berikut:
(int, double) t1 = (17, 3.14);
(double First, double Second) t2 = (0.0, 1.0);
t2 = t1;
Console.WriteLine($"{nameof(t2)}: {t2.First} and {t2.Second}");
// Output:
// t2: 17 and 3.14
(double A, double B) t3 = (2.0, 3.0);
t3 = t2;
Console.WriteLine($"{nameof(t3)}: {t3.A} and {t3.B}");
// Output:
// t3: 17 and 3.14
Anda juga dapat menggunakan operator penugasan = untuk mendekonstruksi instans tuple dalam variabel terpisah. Anda dapat melakukannya dengan salah satu cara berikut:
Secara eksplisit mendeklarasikan jenis setiap variabel di dalam tanda kurung:
var t = ("post office", 3.6); (string destination, double distance) = t; Console.WriteLine($"Distance to {destination} is {distance} kilometers."); // Output: // Distance to post office is 3.6 kilometers.Gunakan kata kunci
vardi luar tanda kurung untuk mendeklarasikan variabel berjenis implisit dan biarkan kompiler menyimpulkan jenisnya:var t = ("post office", 3.6); var (destination, distance) = t; Console.WriteLine($"Distance to {destination} is {distance} kilometers."); // Output: // Distance to post office is 3.6 kilometers.Gunakan variabel yang ada:
var destination = string.Empty; var distance = 0.0; var t = ("post office", 3.6); (destination, distance) = t; Console.WriteLine($"Distance to {destination} is {distance} kilometers."); // Output: // Distance to post office is 3.6 kilometers.
Untuk informasi selengkapnya tentang dekonstruksi tuple dan jenis lainnya, lihat Mendekonstruksi tuple dan jenis lainnya.
Kesetaraan tuple
Dimulai dengan C# 7.3, jenis tuple mendukung operator == dan !=. Operator ini membandingkan anggota operan kiri dengan anggota operan kanan yang sesuai mengikuti urutan elemen tuple.
(int a, byte b) left = (5, 10);
(long a, int b) right = (5, 10);
Console.WriteLine(left == right); // output: True
Console.WriteLine(left != right); // output: False
var t1 = (A: 5, B: 10);
var t2 = (B: 5, A: 10);
Console.WriteLine(t1 == t2); // output: True
Console.WriteLine(t1 != t2); // output: False
Seperti yang ditunjukkan oleh contoh sebelumnya, operasi == dan != tidak mempertimbangkan nama bidang tuple.
Dua tuple sebanding ketika kedua kondisi berikut terpenuhi:
- Kedua tuple memiliki jumlah elemen yang sama. Misalnya,
t1 != t2tidak mengkompilasi jikat1dant2memiliki jumlah elemen yang berbeda. - Untuk setiap posisi tuple, elemen yang sesuai dari operand tuple sebelah kiri dan kanan sebanding dengan operator
==dan!=. Misalnya,(1, (2, 3)) == ((1, 2), 3)tidak mengkompilasi karena1tidak sebanding dengan(1, 2).
Operator == dan != membandingkan tuple dengan cara sirkuit pendek. Artinya, operasi berhenti segera setelah mencapai sepasang elemen yang tidak sama atau mencapai akhir tuple. Namun, sebelum perbandingan apa pun, semua elemen tuple dievaluasi, seperti yang ditunjukkan contoh berikut:
Console.WriteLine((Display(1), Display(2)) == (Display(3), Display(4)));
int Display(int s)
{
Console.WriteLine(s);
return s;
}
// Output:
// 1
// 2
// 3
// 4
// False
Tuple sebagai parameter keluar
Biasanya, Anda merefaktor metode yang memiliki out parameter ke dalam metode yang mengembalikan tuple. Namun, ada kasus di mana parameter out dapat berjenis tuple. Contoh berikut menunjukkan cara bekerja dengan tuple sebagai parameter out:
var limitsLookup = new Dictionary<int, (int Min, int Max)>()
{
[2] = (4, 10),
[4] = (10, 20),
[6] = (0, 23)
};
if (limitsLookup.TryGetValue(4, out (int Min, int Max) limits))
{
Console.WriteLine($"Found limits: min is {limits.Min}, max is {limits.Max}");
}
// Output:
// Found limits: min is 10, max is 20
Tuple vs System.Tuple
Tuple C#, yang didukung oleh jenis System.ValueTuple, berbeda dari tuple yang diwakili oleh jenis System.Tuple. Perbedaan utamanya adalah sebagai berikut:
- jenis
System.ValueTupleadalah jenis nilai. jenisSystem.Tupleadalah jenis referensi. - jenis
System.ValueTupledapat diubah. jenisSystem.Tupletidak dapat diubah. - Anggota data dari jenis
System.ValueTupleadalah bidang. Anggota data dari jenisSystem.Tupleadalah properti.
Spesifikasi bahasa C#
Untuk informasi selengkapnya, lihat catatan proposal fitur berikut ini: