Section Struct, Record, dan Enum sudah membahas sintaks dasar tuple beserta deconstruction, dan section Fungsi dan Method menunjukkan tuple sebagai nilai kembalian method. Bab ini melanjutkan dari sisi lanjutan: bagaimana nama elemen menjadi kontrak yang bertahan menembus signature method, bagaimana tuple berperan sebagai key gabungan dalam Dictionary, dan apa bedanya dengan System.Tuple generik versi lama.

Nama Elemen Lintas Method #

Nama elemen tuple bukan kenyamanan temporer di lokasi deklarasi. Compiler menyimpan nama tersebut pada metadata method lewat TupleElementNamesAttribute, sehingga pemanggil yang menerima nilai kembalian membaca elemen lewat nama itu tanpa perlu melihat isi method.

csharp
(string Min, string Max) CariEkstrem(string[] nama)
{
    string min = nama[0];
    string max = nama[0];
    foreach (string n in nama)
    {
        if (string.Compare(n, min) < 0) min = n;
        if (string.Compare(n, max) > 0) max = n;
    }
    return (min, max);
}

string[] peserta = { "Budi", "Siti", "Andi", "Dewi" };
(string Min, string Max) ekstrem = CariEkstrem(peserta);
Console.WriteLine($"{ekstrem.Min} s.d. {ekstrem.Max}");

Output yang Dihasilkan:

text
Andi s.d. Siti

Mari kita bedah baris demi baris:

  1. CariEkstrem: tipe kembalian ditulis (string Min, string Max); nama Min dan Max menjadi bagian kontrak yang diketahui pemanggil.
  2. ekstrem.Min dan ekstrem.Max: akses elemen memakai nama dari signature method, bukan dari kode di dalam method.
  3. string.Compare: perbandingan ordinal menghasilkan urutan Andi dan Siti dari daftar contoh.

Tuple sebagai Key Dictionary #

ValueTuple mengimplementasikan perbandingan kesetaraan berbasis isi, sehingga satu tuple dapat menjadi key gabungan tanpa tipe tambahan:

csharp
var ongkir = new Dictionary<(string Kota, string Kurir), int>
{
    [("Bandung", "SiCepat")] = 12000,
    [("Bandung", "JNE")] = 15000,
    [("Semarang", "JNE")] = 18000
};
Console.WriteLine(ongkir[("Bandung", "JNE")]);

Output yang Dihasilkan:

text
15000

Compiler menghitung hash dari seluruh elemen tuple, sehingga pasangan ("Bandung", "JNE") dan ("Bandung", "SiCepat") menghasilkan key yang berbeda meski kota asalnya sama.

Deconstruction dan System.Tuple #

Deconstruction dapat mengisi variable yang sudah ada sebelumnya, bukan hanya membentuk variable baru. Setelah itu, bandingkan dengan System.Tuple generik yang berbasis class:

csharp
string terpendek = "";
string terpanjang = "";
(terpendek, terpanjang) = CariEkstrem(peserta);
Console.WriteLine($"{terpendek}/{terpanjang}");

System.Tuple<string, int> lama = System.Tuple.Create("INV-001", 45000);
Console.WriteLine($"{lama.Item1} {lama.Item2}");
Console.WriteLine(ekstrem.GetType());
Console.WriteLine(lama.GetType());

Output yang Dihasilkan:

text
Andi/Siti
INV-001 45000
System.ValueTuple`2[System.String,System.String]
System.Tuple`2[System.String,System.Int32]

Mari kita bedah baris demi baris:

  1. (terpendek, terpanjang) = CariEkstrem(peserta);: deconstruction mengisi dua variable yang sudah dideklarasikan; compiler menyusun ulang nilai berdasar posisi elemen.
  2. lama.Item1 dan lama.Item2: System.Tuple hanya menyediakan property Item1, Item2, dan seterusnya tanpa nama yang bermakna.
  3. GetType(): ekstrem ternyata struct ValueTuple di stack, sedangkan lama berupa object System.Tuple di heap karena berupa reference type.