Episode ini memperluas pengetahuan tipe C#: struct, enum, tuple, dan nullable value types, koleksi seperti Array, List, Dictionary, dan HashSet, dasar LINQ untuk query koleksi, serta nullable reference types untuk null safety yang modern.

Di episode 4 kalian menguasai OOP dengan class dan record. Sekarang kita memperluas perbendaharaan tipe. Developer produksi menghabiskan sebagian besar waktunya bekerja dengan koleksi data — dan C# menyediakan alat yang sangat lengkap untuk ini.
Pemahaman tentang kapan memakai struct versus class, kapan memakai List versus HashSet, dan cara mengekspresikan data yang mungkin tidak ada nilai, akan menentukan kualitas dan keamanan kode kalian.
Episode 5 ini membahas tipe-tipe lanjutan: struct, enum, tuple, dan nullable types, lalu koleksi inti, dilanjutkan dasar LINQ, dan ditutup nullable reference types yang aktif secara default di project modern.
Berbeda dengan class yang merupakan reference type, struct adalah value type — nilainya disalin saat dipindahkan. Struct cocok untuk data kecil yang tidak berubah, seperti koordinat atau besaran:
struct Titik
{
public int X { get; }
public int Y { get; }
public Titik(int x, int y) => (X, Y) = (x, y);
}
enum Ukuran
{
Kecil = 1,
Sedang = 2,
Besar = 3
}
var p = new Titik(10, 20);
var ukuran = Ukuran.Besar;
Console.WriteLine($"{p.X},{p.Y} ukuran {(int)ukuran}");Tuple adalah cara ringkas mengelompokkan beberapa nilai tanpa membuat class baru. Berguna untuk nilai kembalian sederhana:
(int Min, int Max) Batas() => (1, 100);
var batas = Batas();
Console.WriteLine($"Min {batas.Min}, Max {batas.Max}");Tuple (int Min, int Max) memberi nama pada elemen, membuat kode lebih terbaca. Untuk data yang dipakai lintas method dan kelas, tetap pilih record.
Tipe nilai seperti int tidak bisa bernilai null secara normal. Untuk situasi di mana ketiadaan nilai itu bermakna — misalnya tanggal lahir yang belum diisi — gunakan nullable value type dengan tanda tanya:
int? umur = null;
umur = 30;
if (umur.HasValue)
{
Console.WriteLine($"Umur {umur.Value}");
}
else
{
Console.WriteLine("Umur belum diisi.");
}Akses aman bisa dipersingkat dengan umur ?? 0 — operator null-coalescing mengembalikan nilai default saat variabel bernilai null.
Empat koleksi ini menutupi hampir semua kebutuhan:
Array: ukuran tetap, indeks cepat.List<T>: list dinamis yang tumbuh sesuai kebutuhan.Dictionary<TKey, TValue>: pencarian cepat lewat key.HashSet<T>: kumpulan nilai unik dengan operasi himpunan.var angka = new[] { 1, 2, 3 };
var produk = new List<string> { "Kopi", "Teh" };
produk.Add("Susu");
var stok = new Dictionary<string, int>
{
["Kopi"] = 10,
["Teh"] = 5
};
var idUnik = new HashSet<int> { 1, 2, 2, 3 };
Console.WriteLine($"Stok kopi {stok["Kopi"]}, unik {idUnik.Count}");Perhatikan HashSet menolak duplikat: idUnik.Count bernilai 3, bukan 4. Pilih struktur data sesuai pola akses kalian — Dictionary dan HashSet menawarkan pencarian O(1) rata-rata.
LINQ mengubah cara kalian bekerja dengan koleksi. Alih-alih menulis loop manual, kalian mendeskripsikan apa yang diinginkan, bukan bagaimana:
var nilaiSiswa = new List<int> { 55, 78, 90, 62, 88 };
var lulus = nilaiSiswa
.Where(n => n >= 70)
.OrderByDescending(n => n)
.ToList();
Console.WriteLine($"Lulus {lulus.Count} siswa: {string.Join(", ", lulus)}");Operator Where, OrderByDescending, dan ToList adalah contoh deferred execution — query baru dieksekusi saat hasilnya benar-benar dibutuhkan. nilaiSiswa.Where(n => n >= 70) menghasilkan IEnumerable yang dievaluasi saat diiterasi.
Sejak C# 8, nullable reference types (NRT) memberi peringatan saat kalian berpotensi menyalahgunakan null. Project baru mengaktifkannya lewat property Nullable di file .csproj. Cara membacanya: string berarti tidak boleh null, string? berarti boleh null:
string nama = "Arman"; // tidak boleh null
string? kota = null; // boleh null
if (kota is not null)
{
Console.WriteLine($"{nama} tinggal di {kota}");
}Compiler akan memperingatkan jika kalian memakai kota tanpa memeriksa null terlebih dahulu. Guard is not null menegaskan bahwa di dalam blok tersebut, nilai sudah pasti ada.
Inti yang harus dibawa pulang:
?? untuk menangani nilai yang mungkin tidak ada.Di episode 6 selanjutnya kita berurusan dengan hal yang tidak diinginkan tapi pasti terjadi: exception handling dan debugging — try-catch-finally, throw dan custom exception, using declaration untuk resource, debugging di Visual Studio dan VS Code, serta logging dasar.