enum

Konstanta bernama, enum flag, dan konversi.

Daftar isi

enum adalah tipe nilai yang mendefinisikan sekumpulan konstanta bernama untuk daftar pilihan yang tetap, misalnya status pengiriman atau kombinasi izin akses. Penggunaan enum menggantikan angka telanjang dalam kode dengan nama yang berarti, sehingga program lebih mudah dibaca dan nilai yang tidak sah lebih mudah dicegah. Topik ini membahas cara mendeklarasikan enum, cara konversi antara enum, angka, dan teks, serta bentuk enum flag yang menyimpan beberapa pilihan sekaligus dalam satu nilai.

Konstanta bernama dengan enum#

Enum dideklarasikan dengan kata kunci enum, diikuti nama tipenya dan daftar anggotanya. Tanpa penentuan lain, tipe dasarnya adalah int dan penomoran dimulai dari nol, sehingga pada enum StatusPengiriman anggota Menunggu bernilai 0, Diproses bernilai 1, dan seterusnya sesuai urutan penulisannya. Nilai anggota dapat ditentukan secara eksplisit apabila angka yang tetap dibutuhkan, misalnya untuk kesesuaian dengan data lama, dan anggota yang tidak ditentukan meneruskan nilai anggota sebelumnya dengan tambahan satu.

csharp Program.cs
// Program demonstrasi enum, konversinya, dan enum flag
StatusPengiriman status = StatusPengiriman.Diproses;

Console.WriteLine($"status = {status}");
Console.WriteLine($"(int) status = {(int)status}");

StatusPengiriman dariAngka = (StatusPengiriman)2;
Console.WriteLine($"(StatusPengiriman) 2 = {dariAngka}");
Console.WriteLine($"(StatusPengiriman) 99 = {(StatusPengiriman)99}");

bool berhasil = Enum.TryParse("Dikirim", out StatusPengiriman dariTeks);
Console.WriteLine($"TryParse(\"Dikirim\") = {berhasil}, nilai = {dariTeks}");

bool gagal = Enum.TryParse("Terjual", out StatusPengiriman tidakAda);
Console.WriteLine($"TryParse(\"Terjual\") = {gagal}");

Console.WriteLine($"Daftar nama: {string.Join(", ", Enum.GetNames<StatusPengiriman>())}");

Izin izinPustakawan = Izin.Baca | Izin.Tulis;
Console.WriteLine($"izinPustakawan = {izinPustakawan}");
Console.WriteLine($"punya Izin.Tulis -> {izinPustakawan.HasFlag(Izin.Tulis)}");
Console.WriteLine($"punya Izin.Hapus -> {izinPustakawan.HasFlag(Izin.Hapus)}");

izinPustakawan |= Izin.Hapus;
Console.WriteLine($"setelah ditambah Hapus = {izinPustakawan}");

enum StatusPengiriman
{
    Menunggu,
    Diproses,
    Dikirim,
    Selesai
}

[Flags]
enum Izin
{
    Baca = 1,
    Tulis = 2,
    Hapus = 4
}
text Keluaran
status = Diproses
(int) status = 1
(StatusPengiriman) 2 = Dikirim
(StatusPengiriman) 99 = 99
TryParse("Dikirim") = True, nilai = Dikirim
TryParse("Terjual") = False
Daftar nama: Menunggu, Diproses, Dikirim, Selesai
izinPustakawan = Baca, Tulis
punya Izin.Tulis -> True
punya Izin.Hapus -> False
setelah ditambah Hapus = Baca, Tulis, Hapus

Untuk menjalankan program tersebut dari folder topik, gunakan perintah berikut.

bash
# aktifkan .NET yang terpasang di sandbox
export DOTNET_ROOT=/home/kal/.dotnet PATH=/home/kal/.dotnet:$PATH DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1
# jalankan program contoh dari folder topik
dotnet run --file Program.cs
text Keluaran
status = Diproses
(int) status = 1
(StatusPengiriman) 2 = Dikirim
(StatusPengiriman) 99 = 99
TryParse("Dikirim") = True, nilai = Dikirim
TryParse("Terjual") = False
Daftar nama: Menunggu, Diproses, Dikirim, Selesai
izinPustakawan = Baca, Tulis
punya Izin.Tulis -> True
punya Izin.Hapus -> False
setelah ditambah Hapus = Baca, Tulis, Hapus

Keluaran memperlihatkan hubungan dua arah antara nama dan angka. Pencetakan status menampilkan nama Diproses, sedangkan konversi eksplisit dengan (int) menghasilkan angka 1 di belakangnya. Kelas Enum melengkapi kebutuhan lainnya, yaitu metode TryParse mengubah teks menjadi nilai enum dan mengembalikan false apabila teksnya bukan nama anggota mana pun, sedangkan metode GetNames menyajikan seluruh nama anggota untuk keperluan tampilan atau validasi.

Konversi ke dan dari angka#

Konversi antara enum dan angka bersifat eksplisit dua arah. Konversi dari enum ke int dilakukan dengan pengecoran (int), sedangkan konversi sebaliknya memakai pengecoran (StatusPengiriman) di depan angkanya. Perlu dicatat bahwa konversi dari angka ke enum tidak memeriksa keabsahan nilai, sehingga (StatusPengiriman) 99 tetap diterima dan dicetak sebagai 99, yaitu angka yang bukan nama anggota mana pun. Perilaku ini dimungkinkan karena enum pada dasarnya menyimpan angka, dan nilai di luar daftar dapat sah dipakai sebagai wadah kombinasi bit pada enum flag.

Apabila keabsahan nilai perlu diperiksa, kelas Enum menyediakan metode IsDefined yang menguji apakah sebuah angka atau teks termasuk anggota yang terdaftar. Pemeriksaan ini berguna ketika nilai enum berasal dari luar program, misalnya dari berkas konfigurasi atau permintaan jaringan. Tanpa pemeriksaan tersebut, nilai yang tidak sah hanya terlihat ketika program memakainya dan hasilnya tidak sesuai harapan.

Konversi dari teks#

Konversi teks ke enum dilakukan melalui Enum.TryParse, yang mengembalikan bool sebagai penanda keberhasilan dan mengisi variabel keluarannya apabila teks cocok dengan nama salah satu anggota. Bentuk yang mengembalikan bool lebih aman daripada Enum.Parse, karena teks yang tidak dikenal tidak memicu exception, yaitu object error yang dilempar saat program berjalan, melainkan cukup diperiksa dengan pencabangan biasa. Metode Enum.Parse sebaliknya melempar ArgumentException apabila teksnya bukan nama anggota mana pun, sehingga bentuk tersebut hanya tepat apabila kegagalannya memang dianggap kondisi luar biasa. Pada pemanggilan TryParse yang gagal, variabel keluarannya diisi nilai default tipe enum, yaitu anggota bernilai nol, sehingga variabel itu tidak boleh dipakai sebelum keberhasilannya diperiksa. Pola ini menjadikan pemeriksaan teks dari luar program, misalnya permintaan pengguna, dapat ditulis tanpa penanganan exception sama sekali.

csharp Contoh: nilai eksplisit pada anggota enum
// Contoh: nilai eksplisit pada anggota enum
HariKerja hari = HariKerja.Rabu;

Console.WriteLine($"{hari} = {(int)hari}");

enum HariKerja
{
    Senin = 1,
    Selasa = 2,
    Rabu = 3,
    Kamis = 4,
    Jumat = 5
}
text Keluaran
Rabu = 3

Penentuan nilai secara eksplisit seperti pada HariKerja membuat angka di belakang nama menjadi bagian dari kontrak tipe. Nilai tersebut aman disimpan ke berkas atau basis data dan dibaca kembali dengan konversi angka ke enum. Apabila daftar anggota disusun ulang tanpa nilai eksplisit, seluruh nomor di belakangnya ikut bergeser dan data lama salah makna, sehingga nilai eksplisit menjadi kebiasaan yang sehat untuk enum yang tahan lama.

Enum flag#

enum flag adalah enum yang anggotanya menyatakan pilihan yang dapat digabungkan, dan masing-masing anggota memakai nilai pangkat dua, yaitu 1, 2, 4, 8, dan seterusnya. Atribut [Flags] ditempelkan di atas deklarasi agar pencetakan dan pemeriksaan bekerja dengan benar. Beberapa pilihan digabungkan dengan operator bitwise OR |, ditambahkan dengan |=, dan diperiksa dengan metode HasFlag. Keluaran program menunjukkan hasilnya, yaitu izinPustakawan yang awalnya berisi Baca, Tulis berubah menjadi Baca, Tulis, Hapus setelah Hapus ditambahkan, dan pencetakannya menampilkan nama karena atribut [Flags] terpasang.

Nilai pangkat dua bukan aturan kosong, melainkan syarat agar setiap pilihan menempati satu bit yang tidak bertabrakan. Apabila anggota diberi nilai 3 misalnya, nilai tersebut memuat bit milik 1 dan 2 sekaligus, sehingga pemeriksaan HasFlag menjadi tidak dapat dibedakan antara pilihan tunggal dan gabungan. Dengan nilai pangkat dua, satu variabel enum mampu menyimpan banyak pilihan tanpa membuat field terpisah untuk setiap pilihan.

Kesalahan umum#

  • Menyimpan nomor enum ke data lama tanpa menetapkan nilai eksplisit pada anggotanya. Penyusunan ulang daftar anggota menggeser penomoran bawaan, sehingga data yang tersimpan lalu salah makna ketika dibaca kembali.
  • Menggabungkan pilihan pada enum tanpa atribut [Flags] dan tanpa nilai pangkat dua. Pencetakan menampilkan angka mentah, dan pemeriksaan HasFlag menghasilkan jawaban yang menyesatkan karena bitnya bertabrakan.
  • Menugaskan angka langsung ke variabel enum tanpa konversi. Kompilator (compiler) menolaknya dengan error CS0266 karena konversi dari int ke enum wajib eksplisit.
csharp Contoh: penugasan int ke enum yang ditolak kompilator
// tidak-dijalankan
// Contoh: penugasan int ke enum menghasilkan error CS0266
StatusPengiriman status = 2;

enum StatusPengiriman
{
    Menunggu,
    Diproses,
    Dikirim,
    Selesai
}

Ringkasan#

  • enum mendefinisikan konstanta bernama bertipe nilai dengan tipe dasar int secara bawaan, dan penomorannya dimulai dari nol kecuali ditentukan eksplisit.
  • Konversi ke dan dari angka dilakukan dengan pengecoran eksplisit, sedangkan Enum.TryParse mengubah teks dengan aman dan Enum.IsDefined memeriksa keabsahan nilai.
  • Enum flag memakai atribut [Flags] dan nilai pangkat dua agar beberapa pilihan dapat digabungkan dalam satu nilai dan tetap tercetak sebagai daftar nama.

Referensi#