C# 演算子

Tip

この記事は、少なくとも 1 つのプログラミング言語を既に知っており、C# を学習している開発者向けの 基礎 セクションの一部です。 プログラミングを初めて使用する場合は、最初に「 はじめ に」チュートリアルから始めてください。

別の言語から来ていますか? この記事のほとんどの演算子 (+-*/%&&||!==!=<>、比較演算子、および=) は、Java、C++、JavaScript と同じように動作します。 新人にとっての主な驚きは、整数除算の動作、 ++/--のプレフィックス/後置の区別、複合代入が左側の型に戻る方法です。

演算子は、1 つ以上のオペランドを 1 つの値に結合します。 C# 式の式と演算子の優先順位については既にわかっています。この記事では、毎日使用する特定の演算子について詳しく説明します。

算術演算子

5 つの算術演算子は、数値計算を実行します。

Operator 名前 結果
+ 追加 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)

整数除算は 0 に切り捨てられます。 両方のオペランドが整数の場合、/は小数部を破棄します。7 / 23.5ではなく3されます。 切り捨ては、小さい数値ではなくゼロに向かって行われます。 -7 / 2-3 ( -4ではありません)。 10 進数の結果を取得するには、少なくとも 1 つのオペランドを浮動小数点型にします。 7.0 / 23.5。 これは、 / が常に浮動小数点の結果を生成する一部の言語とは異なります。

剰余 (%) は、整数除算した後の余りを返します1なので、10 % 310 = 3 × 3 + 1です。 これは、固定範囲 (index % length) の循環、除数のテスト (n % 2 == 0)、数字の抽出に役立ちます。 負のオペランドの場合、結果の符号は 被除数 の符号 (左オペランド) と一致します。 -7 % 3-17 % -31

単項演算子

単項演算子は、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 (論理否定) — truefalse に、falsetrue に反転させます。 !を頻繁に使用します: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): 最初に変数をインクリメントまたはデクリメントしてから、 新しい 値を返します。
  • 後置 (i++i--): 最初に 現在 の値を返し、次に変数をインクリメントまたはデクリメントします。

++または--がスタンドアロン ステートメント (大きな式の一部ではない) として表示される場合、プレフィックスと後置は同じ効果を持ちます。 この区別は、代入やメソッド引数など、結果が使用される場合にのみ重要です。

関係演算子

関係演算子は 2 つの値を比較し、 boolを返します。

Operator Meaning
< 未満 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'は Unicode 値 66 を持ち、'B''A'は Unicode 値 65 であるため、'A'以上です。数字によって、文字の成績の意味ではなく、比較が決まります。

等値演算子

==!= は、2 つの値が等しいかどうかを確認します。 != は、オペランドが 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の場合、等値は値をテストします。 参照型の場合、既定値は ID (2 つの変数が同じオブジェクトを指しているかどうか) ですが、 stringrecord を含む多くの型は、コンテンツを比較するためにこれをオーバーライドします。 値型、参照型、レコード、構造体間の等価性のしくみの全体像については、「 等値比較」を参照してください。

Note

C# には === 演算子がありません。 ===の記述はコンパイル時エラーです。

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

JavaScript から取得する場合は、値の比較に == を使用します (C# == はプリミティブ型と文字列の値によって既に比較されています)。 よくある関連バグの 1 つは、=(等価性チェック)のつもりで、誤って ==(代入)と書いてしまうことです。 コンパイラは最も一般的な形式をキャッチしますが、=を含む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はスローされません。

条件演算子 ?:

条件演算子 ( 三項 演算子とも呼ばれます) は、条件に基づいて 2 つの式のいずれかを評価します。

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

?:演算子は常に正確に 1 つの分岐を評価します。条件に一致しない側は評価されません。 これにより、その式を条件が適切にガードしている限り、他の入力では失敗するような条件式の片側の式でも安全に使用できます。

単純なインライン選択には、 ?: を使用します。 複数方向の条件またはコード ブロックの場合、通常、 if/else ステートメントがより明確になります。

代入演算子

単純代入演算子 = 変数に値を格納します。

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

C# での代入は 右結合です。つまり、a = b = c = 0 は右から左へ評価されます。c0 が代入され、次に b0 が代入され、最後に a0 が代入されます。

複合代入。

複合代入演算子は、二項演算と代入を組み合わせます。

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

複合代入は、単なる省略記法ではありません。 左側を 1 回だけ 評価し、結果を左側の型に戻します。 これは、左辺に副作用(配列インデクサーなど)がある場合に重要です。また、これが、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# 言語には、特定のシナリオで役立つ演算子が追加されています。

  • シフト演算子 (<<>>>>>) — 整数値のビットを、指定した位置数だけ左または右にシフトします。 ビットごとの論理演算子と整数論理演算子 (&|^~) — 整数値を一度に 1 ビットずつ結合または反転します。フラグ、マスク、および下位レベルのコードで役立ちます。 ビット演算子とシフト演算子
  • checkedunchecked — 整数オーバーフロー時に例外をスローする (checked) か、例外を出さずにラップアラウンドする (unchecked) かを制御します: checked と unchecked
  • Null 演算子 (????=?.?[]) — 既定値を指定したり、メンバー アクセスを短絡評価したりすることで、null 値を安全に扱います: Null 演算子
  • 型テスト演算子と変換演算子 (isastypeof、キャスト (T)) — 値のランタイム型 (型テスト演算子とキャスト演算子) をチェックまたは変換します。
  • 範囲演算子とインデックス演算子 (..^) - 配列とスパンをスライスするための範囲と終了相対インデックスを作成します。 メンバー アクセス演算子と null 条件演算子
  • 分解の割り当て — 1 つの式でタプルまたは型を個々の変数にアンパックする: タプルとその他の型の分解

こちらも参照ください