C# 運算元

Tip

本文屬於 基礎部分, 適合已經至少懂一種程式語言並正在學習 C# 的開發者。 如果你是程式新手,建議先從 入門 教學開始。

來自另一種語言? 本文中的大多數運算子(+*&&%||!/-!=<==>、比較運算子,以及=)的運作方式與 Java、C++ 及 JavaScript 相同。 對新手來說,主要的驚喜是整數除法行為、前綴與後綴的區別 ++/--,以及複合詞分配如何轉換回左側類型。

運算子將一個或多個運算元合併為單一值。 你已經從 C# 表達式中知道表達式和運算子優先順序;本文將更深入介紹你每天會使用的具體操作員。

算術運算子

五個算術運算子執行數值計算。

Operator Name Example 結果
+ 新增 10 + 3 13
- 減法 10 - 3 7
* 乘法 10 * 3 30
/ 部門 10 / 3 3
% 剩餘部分 10 % 3 1
int apples = 10;
int oranges = 3;

Console.WriteLine(apples + oranges);  // => 13  (addition)
Console.WriteLine(apples - oranges);  // => 7   (subtraction)
Console.WriteLine(apples * oranges);  // => 30  (multiplication)
Console.WriteLine(apples / oranges);  // => 3   (integer division: truncates toward zero)
Console.WriteLine(apples % oranges);  // => 1   (remainder)

// Integer division always truncates toward zero — the fractional part is discarded
int result = 7 / 2;
Console.WriteLine(result); // => 3, not 3.5

// Truncation applies to negative results too: -7 / 2 is -3, not -4
int negResult = -7 / 2;
Console.WriteLine(negResult); // => -3

// To get a decimal result, at least one operand must be a double or float
double precise = 7.0 / 2;
Console.WriteLine(precise); // => 3.5

// Remainder with negative operands: the sign of the result matches the dividend
Console.WriteLine(-7 % 3);  // => -1  (-7 = 3 × -2 + (-1))
Console.WriteLine(7 % -3);  // => 1   ( 7 = -3 × -2 + 1)

整數除法會朝零截斷。 當兩個運算元皆為整數時,/ 會捨棄小數部分:7 / 23,不是 3.5。 截斷是朝向零,而非較小的數: -7 / 2-3 (非 -4)。 要得到十進位結果,至少有一個運算元為浮點型態: 7.0 / 23.5。 這與某些語言不同,後者 / 總是產生浮點數結果。

餘數(%)表示整數除法後剩下的部分10 % 31,因為 10 = 3 × 3 + 1。 它對於在固定範圍內循環(index % length)、測試整除性(n % 2 == 0)以及擷取數字都很有用。 對於負運算元,結果的符號與股息的符號(左運算元)相符:-7 % 3-17 % -3且是1

一元運算子

一元運算子作用於單一運算元。

int temperature = 20;
int windChill = -5;

int heatIndex = +temperature;   // unary +: value unchanged (rarely needed)
int coldFactor = -windChill;    // unary -: negates the value → 5

Console.WriteLine(heatIndex);   // => 20
Console.WriteLine(coldFactor);  // => 5

bool isRaining = false;
bool isSunny = !isRaining;     // logical NOT: flips true/false
Console.WriteLine(isSunny);    // => True
  • +x (一元加號)— 保持不變的值;雖然很少明說,但確實有效。
  • -x (一元負號)—— 對該值取負。
  • !x(邏輯 NOT)— 將 true 翻轉為 false,並將 false 翻轉為 true。 你會經常使用!if (!list.Contains(item))

遞增和遞減

++ 加 1,而 -- 減 1。 兩者都有前 形式和 後綴 形式,兩者回傳的值不同:

int counter = 5;

// Prefix: increment first, then use the new value
int a = ++counter;
Console.WriteLine(a);       // => 6
Console.WriteLine(counter); // => 6

// Postfix: use the current value first, then increment
int b = counter++;
Console.WriteLine(b);       // => 6  (value before increment)
Console.WriteLine(counter); // => 7  (incremented after)

// Decrement works the same way
int score = 10;
Console.WriteLine(score--); // => 10 (current value; score becomes 9)
Console.WriteLine(score);   // => 9
  • 前綴++i--i): 先遞增或遞減變數,然後返回 值。
  • Postfixi++i--):先回傳目前值,然後再遞增或遞減該變數。

++-- 作為獨立陳述出現(非較大表達式的一部分)時,前綴與後綴具有相同效果。 這種區別只有在結果被使用時才重要——例如在賦值或方法論元中。

關聯式運算子

關聯運算子比較兩個值並回傳一個 bool

Operator Meaning Example
< 小於 speed < limit
> 大於 speed > limit
<= 小於或等於 score <= 100
>= 大於或等於 score >= 0
int speed = 75;
int limit = 60;

Console.WriteLine(speed > limit);   // => True   (greater than)
Console.WriteLine(speed < limit);   // => False  (less than)
Console.WriteLine(speed >= limit);  // => True   (greater than or equal)
Console.WriteLine(speed <= limit);  // => False  (less than or equal)

// Relational operators work on all numeric types and char
// char comparison uses the character's numeric Unicode code point, not alphabetical position
// 'B' (U+0042, value 66) is less than 'A' (U+0041, value 65)? No — 'A' (65) < 'B' (66)
char grade = 'B';
Console.WriteLine(grade >= 'A' && grade <= 'C'); // => True  ('A'=65 <= 'B'=66 <= 'C'=67)

關聯運算子適用於所有數值類型和 char。 對於 char,比較時使用的是該字元的 Unicode 碼位數值,而不是任何字母順序或特定領域的排序規則。 在上述成績範例中,'B' 大於或等於 'A',因為 'B' 的 Unicode 值是 66,而 'A' 的 Unicode 值是 65——由 數字 決定比較結果,而不是由字母成績的意義決定。

等號比較運算子

==!= 檢查兩個值是否相等。 != 在運算元相等時為 true,相等時為 false

int expected = 42;
int actual = 42;

Console.WriteLine(actual == expected);  // => True   (values are equal)
Console.WriteLine(actual != expected);  // => False  (true when values are not equal)

string name = "Alice";
Console.WriteLine(name == "Alice");  // => True   (string content matches)
Console.WriteLine(name == "alice");  // => False  (case-sensitive)

int x = 5;
Console.WriteLine(x == 10);  // => False

對於數值類型和 string,相等性會測試其值。 對於參考型別,預設為同一型態(是否兩個變數指向同一物件),但許多型別包含stringrecord並覆寫此值以比較內容。 完整情況——平等如何在值類型、參考類型、記錄與結構間運作——請參見 平等比較

Note

C# 沒有 === 運算子。 寫入 === 是編譯時的錯誤:

// This does not compile — C# has no === operator
bool same = (x === 10);

如果你原本使用 JavaScript,建議使用 == 來比較值(C# 的 == 對基本型別和字串本來就是以值來比較)。 一個常見的相關錯誤是,原本想寫 ==(相等性檢查),卻不小心寫成 =(指定)。 編譯器會偵測出最常見的情況,但請再次檢查任何包含 if= 條件。

條件邏輯運算子

&& (AND)和 || (OR)結合 bool 表達式。

int age = 20;
bool hasTicket = true;

// && (AND): both sides must be true
bool canEnter = age >= 18 && hasTicket;
Console.WriteLine(canEnter); // => True

// || (OR): at least one side must be true
bool freeEntry = age < 5 || age >= 65;
Console.WriteLine(freeEntry); // => False

// Short-circuit: right side is skipped when the result is already determined
// Here, items.Count is never called if items is null
List<string>? items = null;
bool hasItems = items != null && items.Count > 0;
Console.WriteLine(hasItems); // => False  (short-circuits; no NullReferenceException)

兩種運算子都會 短路:當結果已經確定時,他們會跳過正確運算元的評估。

  • && 會在左側為 false 時立即傳回 false。 右側從不被評估。
  • || 會在左側為 true 時立即返回 true。 右側從不被評估。

短路行為有一項實際上的好處:如上述範例所示,你可以用左側的 null 檢查來安全地防護右側的運算。 若 itemsnull,則 && 會在此停止 — items.Count 永遠不會被呼叫,因此不會拋出 NullReferenceException

條件運算子 ?:

條件運算子(也稱為 三元 運算子)根據條件評估兩種表達式中的一種:

condition ? value-when-true : value-when-false
int temperature2 = 35;

// condition ? value-when-true : value-when-false
string weather = temperature2 > 30 ? "hot" : "comfortable";
Console.WriteLine(weather); // => hot

// Only the matching branch evaluates — the other branch is never run
int divisor = 0;
// The division 10 / divisor is never evaluated because divisor == 0 is true
int safe = divisor == 0 ? -1 : 10 / divisor;
Console.WriteLine(safe); // => -1

操作員 ?: 總是只評估一個分支——不符合條件的那一側則不被評估。 這讓你可以安全地在其中一側使用某個在其他輸入情況下會失敗的運算式,只要條件有正確地加以保護。

使用 ?: 來做簡單的行內選項。 對於多向條件或程式碼區塊,陳述 if/else 通常會更清晰。

指派運算子

簡單的指派運算子 = 將一個變數儲存一個值:

int level = 1;  // declaration + initialization
level = 5;      // reassignment

C# 中的賦值是右結合的,這表示a = b = c = 0會由右至左進行求值:c被指派為0,然後b被指派為a,接著0被指派為0

複合指派

複合指派算子將二元運算與指派結合:

Operator 相當於
x += y x = x + y
x -= y x = x - y
x *= y x = x * y
x /= y x = x / y
x %= y x = x % y
int level = 1;
level = 5;          // simple assignment: replaces the value
Console.WriteLine(level); // => 5

// Compound assignment: short form of binary operation + assignment
int hp = 100;
hp += 20;   // same as: hp = hp + 20
Console.WriteLine(hp); // => 120
hp -= 10;   // same as: hp = hp - 10
Console.WriteLine(hp); // => 110
hp *= 2;    // same as: hp = hp * 2
Console.WriteLine(hp); // => 220
hp /= 3;    // same as: hp = hp / 3 (integer division)
Console.WriteLine(hp); // => 73
hp %= 7;    // same as: hp = hp % 7
Console.WriteLine(hp); // => 3

複合作業不僅僅是一種簡寫。 它只對左側進行 一次 評估,然後將結果轉換回左側類型。 當左側具有副作用(例如陣列索引子)時,這一點就很重要;這也是為什麼對 byte 變數進行複合指派時,無須明確轉型也能通過編譯,但展開後的寫法則不行:

// Assignment is right-associative: evaluated right to left
int a2, b2, c2;
a2 = b2 = c2 = 0;     // c2 = 0 first, then b2 = 0, then a2 = 0
Console.WriteLine($"{a2} {b2} {c2}"); // => 0 0 0

// Compound assignment evaluates the left side once and converts back to the LHS type
byte small = 200;
small += 10;  // equivalent to: small = (byte)(small + 10); result is 210
Console.WriteLine(small); // => 210

small += 10 編譯是因為編譯器會自動插入縮小轉換——結果 210,位於 byte 0–255 的範圍內。 small = small + 10 會需要明確轉型為 (byte),因為算術運算會將兩個運算元都提升為 int

其他 C# 運算子

本文介紹你在日常程式碼中最常遇到的運算元。 C# 語言包含更多在特定情境下有用的運算子:

  • 移位運算子<<>>>>>) — 將整數值的位元向左或向右移動指定位置。 位元運算與整數邏輯運算子&|^~)— 以每次一個位元的方式組合或反轉整數值,適用於旗標、遮罩及低階程式碼:位元與移位運算子
  • checked 以及 unchecked — 控制整數溢位是否拋出例外(checked)或靜默繞行(unchecked): 已檢查與未檢查
  • Null 運算子????=?.?[])— 透過提供預設值或讓成員存取短路,安全地處理 null 值:Null 運算子
  • 型別測試與轉換運算子isastypeof, cast (T)) — 檢查或轉換值的執行時類型: 型別測試與鑄造運算元
  • 範圍與索引運算子..^) — 建立範圍與終點相對索引以切片陣列與範圍: 成員存取與空條件運算元
  • 解構指派 — 將元組或型別拆包成單一變數,僅用一個表達式:解構元組及其他型

另請參閱