Jenis tuple (referensi C#)
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.
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.
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:
int[] xs = new int[] { 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
int[] ys = new int[] { -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.");
}
// Initialize min to MaxValue so every value in the input
// is less than this initial value.
var min = int.MaxValue;
// Initialize max to MinValue so every value in the input
// is greater than this initial value.
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. Di API publik, pertimbangkan untuk menentukan kelas atau jenis struktur .
Nama bidang Tuple
Anda secara eksplisit menentukan nama bidang tuple 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}.");
Jika Anda tidak menentukan nama bidang, nama bidang tersebut mungkin 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 disebut penginisialisasi 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 sebelumnya, 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.
Dimulai dengan C# 12, Anda dapat menentukan alias untuk jenis tuple dengan using
direktif. Contoh berikut menambahkan global using
alias untuk jenis tuple dengan dua nilai bilangan bulat untuk nilai dan Max
yang diizinkanMin
:
global using BandPass = (int Min, int Max);
Setelah mendeklarasikan alias, Anda dapat menggunakan nama sebagai alias untuk jenis tuple tersebut BandPass
:
BandPass bracket = (40, 100);
Console.WriteLine($"The bandpass filter is {bracket.Min} to {bracket.Max}");
Alias tidak memperkenalkan jenis baru, tetapi hanya membuat sinonim untuk jenis yang ada. Anda dapat mendekonstruksi tuple yang dideklarasikan dengan BandPass
alias sama seperti yang Anda bisa dengan jenis tuple yang mendasarnya:
(int a , int b) = bracket;
Console.WriteLine($"The bracket is {a} to {b}");
Seperti halnya tugas tuple atau dekonstruksi, nama anggota tuple tidak perlu cocok; jenisnya.
Demikian pula, alias kedua dengan aritas dan jenis anggota yang sama dapat digunakan secara bergantian dengan alias asli. Anda dapat mendeklarasikan alias kedua:
using Range = (int Minimum, int Maximum);
Anda dapat menetapkan Range
tuple ke BandPass
tuple. Seperti semua tugas tuple, nama bidang tidak perlu cocok, hanya jenis dan aritas.
Range r = bracket;
Console.WriteLine($"The range is {r.Minimum} to {r.Maximum}");
Alias untuk jenis tuple memberikan informasi yang lebih semantik saat Anda menggunakan tuple. Ini tidak memperkenalkan jenis baru. Untuk memberikan keamanan jenis, Anda harus mendeklarasikan posisi sebagai record
gantinya.
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 banyak cara:
Gunakan kata kunci
var
di 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.
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.
Nyatakan beberapa jenis secara eksplisit dan jenis lainnya secara implisit (dengan
var
) di dalam tanda kurung:var t = ("post office", 3.6); (var destination, double 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.
Tujuan ekspresi dekonstruksi dapat mencakup variabel dan variabel yang ada yang dideklarasikan dalam deklarasi dekonstruksi.
Anda juga dapat menggabungkan dekonstruksi dengan pencocokan pola untuk memeriksa karakteristik bidang dalam tuple. Contoh berikut mengulang melalui beberapa bilangan bulat dan mencetak bilangan bulat yang dapat dibagi 3. Ini mendekonstruksi hasil Int32.DivRem tuple dan kecocokan terhadap Remainder
0:
for (int i = 4; i < 20; i++)
{
if (Math.DivRem(i, 3) is ( Quotient: var q, Remainder: 0 ))
{
Console.WriteLine($"{i} is divisible by 3, with quotient {q}");
}
}
Untuk informasi selengkapnya tentang dekonstruksi tuple dan jenis lainnya, lihat Mendekonstruksi tuple dan jenis lainnya.
Kesetaraan tuple
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 != t2
tidak mengkompilasi jikat1
dant2
memiliki 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 dikompilasi karena1
tidak 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.ValueTuple
adalah jenis nilai. jenisSystem.Tuple
adalah jenis referensi. - jenis
System.ValueTuple
dapat diubah. jenisSystem.Tuple
tidak dapat diubah. - Anggota data dari jenis
System.ValueTuple
adalah bidang. Anggota data dari jenisSystem.Tuple
adalah properti.
Spesifikasi bahasa C#
Untuk informasi selengkapnya, lihat: