Ekspresi C#

Tip

Artikel ini adalah bagian dari bagian Dasar-Dasar untuk pengembang yang sudah mengetahui setidaknya satu bahasa pemrograman dan mempelajari C#. Jika Anda baru menggunakan pemrograman, mulailah dengan tutorial Memulai terlebih dahulu.

Berasal dari bahasa lain? Ekspresi dalam C# berfungsi seperti yang mereka lakukan di Java, C++, dan JavaScript. Satu perbedaan yang perlu diperhatikan: operator penugasan gabungan seperti += dan operator inkremen ++ merupakan ekspresi dalam C#, sehingga dapat muncul dalam ekspresi yang lebih kompleks.

Ekspresi adalah bagian dari kode yang dievaluasi pengkompilasi untuk menghasilkan nilai — angka, string, referensi, atau bool. Misalnya, 3 + 4 * 2 adalah ekspresi yang mengevaluasi ke bilangan bulat 11, dan total > 10 merupakan ekspresi yang mengevaluasi ke true atau false.

Ekspresi paling sederhana adalah literal (seperti 42 atau "hello") dan nama variabel (seperti total). Anda membangun ekspresi yang lebih kompleks dengan menggabungkan ekspresi yang lebih sederhana dengan operator.

Ekspresi dan pernyataan

Ekspresi menghasilkan nilai. Pernyataan adalah instruksi lengkap yang dijalankan program. Banyak pernyataan berisi ekspresi. Misalnya, int total = 3 + 4 * 2; adalah pernyataan deklarasi variabel. Pengkompilasi mengevaluasi ekspresi 3 + 4 * 2penginisialisasi , yang menghasilkan 11, dan menetapkan nilai tersebut ke variabel totalbaru .

Anda dapat memikirkan ekspresi seperti frasa dan pernyataan C# seperti kalimat lengkap. Definisi kerja ini membantu Anda memahami terminologi formal dan penjelasan yang akan Anda temui saat Anda mempelajari lebih lanjut tentang C#, meskipun pengkodean biasa jarang mengharuskan Anda untuk mengingat perbedaan secara sadar.

Menggabungkan ekspresi

Ekspresi dapat digabungkan. Pertimbangkan 3 + 4 * 2. Ekspresi tunggal ini sebenarnya berisi dua ekspresi yang lebih kecil: ekspresi 4 * 2perkalian dan ekspresi3 + <result> penambahan. Ketika ekspresi digabungkan, C# memerlukan aturan untuk memutuskan mana yang akan dievaluasi terlebih dahulu. Aturan itu adalah prioritas operator.

Anda tidak perlu menghafal hierarki prioritas lengkap. Bagian berikutnya meringkas grup sehari-hari, dan tanda kurung selalu memungkinkan Anda membuat pesanan eksplisit saat Anda tidak yakin.

Prioritas operator

Prioritas operator menentukan bagaimana ekspresi gabungan dikelompokkan ke dalam sub-ekspresi. Konsep ini mirip dengan aturan urutan operasi dari kelas matematika. Operator dengan prioritas yang lebih tinggi mengikat lebih erat ke operannya. Ekspresi disusun seolah-olah operan tersebut dikurung bersama-sama. Dalam 3 + 4 * 2, * memiliki prioritas yang lebih tinggi daripada +, sehingga ekspresi mengelompokkan sebagai 3 + (4 * 2), bukan (3 + 4) * 2.

C# memiliki lebih banyak grup prioritas daripada empat yang dirangkum di sini. Grup tambahan tersebut memberlakukan aturan yang familier — misalnya, perkalian sebelum penambahan — dan mencakup kumpulan operator lengkap. Grup berikut mencakup apa yang paling sering Anda temui dalam kode sehari-hari:

  1. Primer, unary, dan range — ini adalah tiga grup prioritas yang berbeda, yang semuanya mengikat lebih ketat daripada aritmatika. Ringkasan ini menggabungkannya menjadi satu langkah karena, untuk tujuan praktis, semuanya berlaku sebelum aritmatika.
    • Operator utama — akses anggota (x.y), panggilan metode (f()), pengindeksan (a[i]), dan akses bersyarat null (?., ?[]) — mengikat paling erat dari semua.
    • Operator unari beroperasi pada satu operand: negasi (-x), negasi logis (!flag), increment prefix (++i), dan increment postfix (i++).
    • Operator rentang (..) membentuk rentang indeks untuk ekspresi slice, seperti array[1..4].
  2. Aritmatika*, /, % ikat lebih erat daripada + dan -. Perkalian dan pembagian terjadi sebelum penambahan dan pengurangan.
  3. Perbandingan<, >, <=, >=, ==, != memiliki ikatan yang lebih lemah daripada aritmatika, sehingga operasi aritmetika diselesaikan terlebih dahulu sebelum perbandingan.
  4. Logis&& dan || mengikat operator umum yang paling tidak erat, sehingga perbandingan selesai sebelum kombinasi logis.

Urutan prioritas ini berarti ekspresi score + bonus > threshold && attempts < maxAttempts dievaluasi persis seperti saat Anda membacanya: tambahkan score dan bonus, bandingkan hasilnya dengan threshold, bandingkan attempts dengan maxAttempts, lalu gabungkan dua hasil bool dengan &&. Menambahkan tanda kurung untuk membuat setiap pengelompokan eksplisit menunjukkan struktur yang sama: ((score + bonus) > threshold) && (attempts < maxAttempts).

Untuk hierarki prioritas lengkap yang mencakup setiap operator, lihat operator dan ekspresi C#.

Gunakan tanda kurung untuk memperjelas niat

Tanda kurung mengambil alih prioritas dan mendokumentasikan niat Anda secara bersamaan. Saat pesanan tidak jelas dari grup di atas, tambahkan tanda kurung:

int score = 80;
int bonus = 15;
int threshold = 90;
bool eligible = true;

// Without parentheses: || binds less tightly than &&, so this reads as:
//   eligible && (score + bonus > threshold) || bonus > 20
bool result1 = eligible && score + bonus > threshold || bonus > 20;

// With parentheses: forces the || to combine two complete conditions
bool result2 = (eligible && score + bonus > threshold) || bonus > 20;

Console.WriteLine(result1); // => True
Console.WriteLine(result2); // => True

// Parentheses can also change the result:
bool isAdmin = false;
bool isOwner = true;

// Without: && binds tighter, so: (isAdmin && isOwner) || true
bool access1 = isAdmin && isOwner || true;
// With: forces the || to run first
bool access2 = isAdmin && (isOwner || true);

Console.WriteLine(access1); // => True   (false && true is false; false || true is true)
Console.WriteLine(access2); // => False  (false && anything is false)

Dua baris terakhir menunjukkan bahwa tanda kurung dapat mengubah hasilnya, bukan hanya gaya. Saat && dan || muncul bersamaan, tambahkan tanda kurung untuk mengeja kondisi mana yang digabungkan terlebih dahulu. Pembaca yang melihat (isAdmin && isOwner) || isSuperUser segera mengetahui niatnya.

Bagaimana ekspresi dievaluasi

Memahami bagaimana C# mengevaluasi ekspresi gabungan lebih mudah dengan analogi. Pertimbangkan untuk bekerja melalui masalah matematika yang kompleks dengan pensil dan kertas: Anda mengidentifikasi sub-ekspresi terdalam atau paling diutamakan tertinggi, menghitung nilai sementaranya, menuliskan hasilnya, lalu ulangi dengan sub-ekspresi berikutnya — melanjutkan hingga Anda mencapai jawaban akhir.

C# mengikuti proses yang sama, dipandu oleh dua aturan:

Aturan 1: Operand dievaluasi dari kiri ke kanan. Untuk ekspresi biner apa pun, kedua operan harus dievaluasi sepenuhnya sebelum operator diterapkan. C# mengevaluasi operand kiri terlebih dahulu, lalu kanan, lalu melakukan operasi.

Aturan 2: Beberapa operator sirkuit pendek. Operator tertentu berhenti mengevaluasi segera setelah hasilnya ditentukan, melewati operan yang tersisa:

  • && (AND kondisional): mengembalikan false segera setelah sisi kiri bernilai false. Sisi kanan tidak pernah dievaluasi.
  • || (OR kondisional): mengembalikan true segera setelah sisi kiri bernilai true. Sisi kanan tidak pernah dievaluasi.
  • ?: (kondisional/ternary): hanya mengevaluasi cabang yang cocok dengan kondisi — cabang lain tidak pernah dievaluasi.
  • ?. (akses anggota bersyarat null) dan ?[] (akses elemen bersyarat null): berhenti dan segera mengembalikan null jika sisi kiri bernilai null, tanpa mengakses anggota atau indeks.
  • ??= (penugasan null-coalescing): menetapkan sisi kanan hanya ketika sisi kiri adalah null.

Evaluasi berbasis kertas dan pensil

Pertimbangkan ekspresi 3 + 6 / 2. Meskipun penambahan muncul terlebih dahulu dalam urutan membaca, / memiliki prioritas yang lebih tinggi daripada +, jadi 6 / 2 adalah sub-ekspresi yang mengevaluasi terlebih dahulu. Mengerjakannya selangkah demi selangkah — persis seperti yang Anda lakukan di atas kertas:

3 + 6 / 2
      ↓   (evaluate 6 / 2 → 3)
3 +   3
  ↓   (evaluate 3 + 3 → 6)
  6
// 3 + 6 / 2
// Step 1: 6 / 2 has higher precedence → interim value 3
// Step 2: 3 + 3 → final result 6
int result = 3 + 6 / 2;
Console.WriteLine(result); // => 6

Nilai sementara 3 yang dihasilkan oleh 6 / 2 menjadi operan yang tepat dari +, dan hasil akhirnya adalah 6. Setiap sub-ekspresi menghasilkan nilai sementara; nilai sementara tersebut memberi umpan sub-ekspresi berikutnya, sampai hanya satu nilai yang tersisa.

Associativity adalah konsep terkait: ketika dua operator memiliki prioritas yang sama, associativity memutuskan mana yang lebih dulu. Sebagian besar operator C# adalah asosiatif kiri, yang berarti mereka mengelompokkan dari kiri ke kanan. Jadi a - b - c sama (a - b) - cdengan , bukan a - (b - c).

Evaluasi sirkuit pendek dalam praktik

Evaluasi sirkuit pendek sangat berguna untuk pemeriksaan null:

string? text = null;

// Safe: second condition runs only when text is not null
bool hasContent = text != null && text.Length > 0;
Console.WriteLine(hasContent); // => False  (short-circuits after null check; no NullReferenceException)

text = "hello";
hasContent = text != null && text.Length > 0;
Console.WriteLine(hasContent); // => True

// || short-circuits on true: right side is never evaluated when left side is true
string word = "hello";
bool anyMatch = word.StartsWith("h") || word.StartsWith("x");
Console.WriteLine(anyMatch); // => True  (right side never evaluated)

// ?. short-circuits on null: returns null without accessing .Length
string? maybeNull = null;
int? length = maybeNull?.Length;   // length is null; no NullReferenceException
Console.WriteLine(length.HasValue); // => False

text != null && text.Length > 0 aman karena kondisi kedua hanya berjalan ketika text bukan null. Demikian pula, ?. menghentikan evaluasi saat menemukan referensi null, sehingga menghindari NullReferenceException tanpa pemeriksaan if yang eksplisit.

Untuk pembahasan yang lebih luas tentang operator null-safe, lihat operator null di C#.

Baca juga