演算子(C#)
算術演算子・比較演算子・論理演算子をまとめて解説します。『C#』では演算子の種類が豊富で、整数除算の挙動や文字列への + 演算子の挙動など、他の言語と異なる点があります。Nullable 型との組み合わせやビット演算子についても確認しておきましょう。
算術演算子
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
+ | 加算。文字列の場合は連結。 | 850 + 150 | 1000 |
- | 減算。 | 850 - 50 | 800 |
* | 乗算。 | 850 * 2 | 1700 |
/ | 除算。整数同士の場合は結果も整数(小数部切り捨て)。 | 850 / 4 | 212 |
% | 剰余(余り)。 | 850 % 7 | 3 |
++ | インクリメント。値を1増やします。 | level++ | level + 1 |
-- | デクリメント。値を1減らします。 | level-- | level - 1 |
整数同士の / は結果も整数になります。850 / 4 の結果は 212 であり、212.5 にはなりません。浮動小数点数の結果が必要な場合は、どちらか一方を double や float にキャストしてください(例: (double)850 / 4)。
string に対する + 演算子は文字列連結になります。数値と文字列を + でつなぐと、数値が自動的に文字列に変換されて連結されます(例: "スコア: " + 850 → "スコア: 850")。
比較演算子
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
== | 等しい。 | score == 850 | true / false |
!= | 等しくない。 | score != 0 | true / false |
> | より大きい。 | score > 850 | true / false |
>= | 以上。 | score >= 850 | true / false |
< | より小さい。 | score < 850 | true / false |
<= | 以下。 | score <= 850 | true / false |
比較演算子はすべて bool 型の値(true または false)を返します。string の == は参照ではなく文字列の内容(値)で比較されます。これは C# の string が == 演算子をオーバーロードしているためで、Java の .equals() のような特別なメソッドを使う必要はありません。
論理演算子
| 演算子 | 意味 | 説明 |
|---|---|---|
&& | 論理AND(かつ) | 左辺と右辺がともに true のとき true。左辺が false なら右辺は評価しません(短絡評価)。 |
|| | 論理OR(または) | 左辺か右辺のどちらかが true のとき true。左辺が true なら右辺は評価しません(短絡評価)。 |
! | 論理NOT(否定) | true を false に、false を true に反転させます。 |
&& と || は短絡評価(ショートサーキット評価)を行います。&& では左辺が false の時点でそれ以上の評価を打ち切り、|| では左辺が true の時点で評価を打ち切ります。この特性を利用して、null チェックを先に書いてから安全にメンバーへアクセスするパターンがよく使われます(例: obj != null && obj.IsValid)。
ビット演算子
| 演算子 | 意味 | 例 | 結果(2進数) |
|---|---|---|---|
& | ビットAND | 0b1010 & 0b1100 | 0b1000(8) |
| | ビットOR | 0b1010 | 0b1100 | 0b1110(14) |
^ | ビットXOR | 0b1010 ^ 0b1100 | 0b0110(6) |
~ | ビット反転(NOT) | ~0b00000001 | 全ビット反転 |
<< | 左シフト | 1 << 3 | 8(2³) |
>> | 右シフト | 8 >> 1 | 4 |
ビット演算子は主にフラグ管理([Flags] 属性と enum の組み合わせ)やパフォーマンスが重要な低レイヤー処理で使われます。ゲーム開発では複数の状態フラグを1つの整数値でまとめて管理する場面で役立ちます。
Nullable 型と演算子の組み合わせ
int? のような Nullable 型に対して算術演算子や比較演算子を使う際は注意が必要です。Nullable 型の変数が null の場合、算術演算の結果も null になります。比較演算子では null との比較は常に false を返すため、null チェックには == null または is null を使いましょう。
// Nullable型(int?)と演算子の例です。
int? hp = null;
// null に算術演算子を適用すると結果もnullになります。
int? result = hp + 100;
// null 合体演算子でデフォルト値を与えます。
int actualHp = hp ?? 0; // hp が null なら 0 を使います。
// null チェックには == null か is null を使います。
if (hp == null) {
// hp が null のときの処理です。
}
サンプルコード
ArithmeticOperators.cs
using System;
class ArithmeticOperators {
static void Main() {
// --- 基本的な算術演算子 ---
int scoreA = 850;
int bonus = 150;
Console.WriteLine("=== 算術演算子の基本 ===");
Console.WriteLine("加算(+): " + (scoreA + bonus)); // 1000
Console.WriteLine("減算(-): " + (scoreA - bonus)); // 700
Console.WriteLine("乗算(*): " + (scoreA * 2)); // 1700
Console.WriteLine("剰余(%): " + (scoreA % 7));
// --- 整数除算の挙動 ---
// 整数同士の割り算は小数部が切り捨てられます。
Console.WriteLine("\n=== 整数除算 ===");
int intDiv = scoreA / 4; // 整数除算: 212(小数部なし)。
double doubleDiv = (double)scoreA / 4; // キャストで浮動小数点除算: 212.5。
Console.WriteLine("int / int: " + intDiv); // 212
Console.WriteLine("double / int: " + doubleDiv); // 212.5
// 割り切れない場合に違いが現れます。
int intRemainder = 850 / 7; // 121(0.42... が切り捨て)。
double doubleRemainder = (double)850 / 7; // 121.4285...
Console.WriteLine("850 / 7 (int): " + intRemainder); // 121
Console.WriteLine("850 / 7 (double): " + doubleRemainder); // 121.42857142857143
// --- インクリメント・デクリメント ---
Console.WriteLine("\n=== インクリメント・デクリメント ===");
int level = 1;
Console.WriteLine("初期 level: " + level); // 1
level++; // 後置インクリメント: 式の評価後に加算します。
Console.WriteLine("level++ 後: " + level); // 2
++level; // 前置インクリメント: 式の評価前に加算します。
Console.WriteLine("++level 後: " + level); // 3
level--; // 後置デクリメント: 式の評価後に減算します。
Console.WriteLine("level-- 後: " + level); // 2
// 前置と後置の違いは式の中で使うときに現れます。
int a = 5;
int b = a++;
Console.WriteLine("a = " + a + ", b = " + b); // a=6, b=5
int c = 5;
int d = ++c;
Console.WriteLine("c = " + c + ", d = " + d); // c=6, d=6
// --- 文字列への + 演算子 ---
// 文字列と数値を + でつなぐと、数値は自動的に文字列に変換されます。
Console.WriteLine("\n=== 文字列への + 演算子 ===");
string name = "item_a";
int score = 850;
string msg = name + "のスコアは" + score + "です。"; // 数値が文字列に変換されます。
Console.WriteLine(msg);
// 数値同士を先に足してから連結することで意図通りの結果になります。
Console.WriteLine("合計: " + (score + 150)); // 合計: 1000(数値の加算)。
Console.WriteLine("合計: " + score + 150); // 合計: 850150(文字列連結)。
}
}
コンパイルして実行すると次のようになります。
dotnet script ArithmeticOperators.cs === 算術演算子の基本 === 加算(+): 1000 減算(-): 700 乗算(*): 1700 剰余(%): 3 === 整数除算 === int / int: 212 double / int: 212.5 850 / 7 (int): 121 850 / 7 (double): 121.42857142857143 === インクリメント・デクリメント === 初期 level: 1 level++ 後: 2 ++level 後: 3 level-- 後: 2 a = 6, b = 5 c = 6, d = 6 === 文字列への + 演算子 === item_aのスコアは850です。 合計: 1000 合計: 850150
ComparisonLogicalOperators.cs
using System;
class ComparisonLogicalOperators {
static void Main() {
// --- 比較演算子 ---
int scoreA = 850;
int scoreB = 720;
int scoreC = 930;
Console.WriteLine("=== 比較演算子 ===");
Console.WriteLine("scoreA == scoreB: " + (scoreA == scoreB)); // False
Console.WriteLine("scoreA != scoreB: " + (scoreA != scoreB)); // True
Console.WriteLine("scoreA > scoreB: " + (scoreA > scoreB)); // True
Console.WriteLine("scoreA >= scoreC: " + (scoreA >= scoreC)); // False
Console.WriteLine("scoreA < scoreC: " + (scoreA < scoreC)); // True
Console.WriteLine("scoreA <= scoreC: " + (scoreA <= scoreC)); // True
// --- string の == は値(内容)で比較されます ---
Console.WriteLine("\n=== string の比較 ===");
string name1 = "item_a";
string name2 = "item_a";
string name3 = "item_b";
Console.WriteLine("name1 == name2: " + (name1 == name2)); // True(内容が同じ)。
Console.WriteLine("name1 == name3: " + (name1 == name3)); // False(内容が異なる)。
// --- 論理演算子 ---
Console.WriteLine("\n=== 論理演算子 ===");
bool isActive = true;
bool hasBoost = true;
bool hasOption = false;
// &&(AND): 両方がtrueのときtrueになります。
bool optionEnabled = isActive && hasOption;
Console.WriteLine("オプション有効(アクティブ && オプションあり): " + optionEnabled); // False
// ||(OR): どちらかがtrueのときtrueになります。
bool isStrong = isActive || hasBoost;
Console.WriteLine("有効(アクティブ || ブーストあり): " + isStrong); // True
// !(NOT): 値を反転させます。
bool isInactive = !isActive;
Console.WriteLine("非アクティブ(!アクティブ): " + isInactive); // False
// --- 複合条件 ---
Console.WriteLine("\n=== 複合条件 ===");
// 合格判定(複合条件の例)。
int threshold = 900;
bool passes = isActive && (scoreA >= threshold || hasBoost);
Console.WriteLine("合格条件(アクティブ && (スコア十分 || ブーストあり)): " + passes); // True
// --- 短絡評価(ショートサーキット評価)---
// &&: 左辺がfalseなら右辺は評価されません。
// ||: 左辺がtrueなら右辺は評価されません。
Console.WriteLine("\n=== 短絡評価 ===");
// null チェックと組み合わせた安全なアクセスパターンです。
string targetName = "item_x";
bool hasLongName = targetName != null && targetName.Length > 3;
// targetName が null なら targetName.Length は評価されないためNullReferenceExceptionが起きません。
Console.WriteLine("名前が3文字より長い: " + hasLongName); // True(6文字)。
// null の場合は短絡評価で右辺をスキップします。
string nullName = null;
bool isNullLong = nullName != null && nullName.Length > 3;
Console.WriteLine("null の名前が3文字より長い: " + isNullLong); // False(右辺は評価されない)。
}
}
コンパイルして実行すると次のようになります。
dotnet script ComparisonLogicalOperators.cs === 比較演算子 === scoreA == scoreB: False scoreA != scoreB: True scoreA > scoreB: True scoreA >= scoreC: False scoreA < scoreC: True scoreA <= scoreC: True === string の比較 === name1 == name2: True name1 == name3: False === 論理演算子 === オプション有効(アクティブ && オプションあり): False 有効(アクティブ || ブーストあり): True 非アクティブ(!アクティブ): False === 複合条件 === 合格条件(アクティブ && (スコア十分 || ブーストあり)): True === 短絡評価 === 名前が3文字より長い: True null の名前が3文字より長い: False
NullableOperators.cs
using System;
class NullableOperators {
static void Main() {
// --- Nullable型と算術演算子 ---
// int? は null を代入できる整数型です。
int? valueA = 1000; // 値Aです(値あり)。
int? valueB = null; // 値Bです(未確認のためnull)。
Console.WriteLine("=== Nullable型と算術演算子 ===");
// Nullable型に算術演算子を使うと null が伝播します。
int? resultA = valueA + 500; // 値がある場合は通常通り計算されます。
int? resultB = valueB + 500;
Console.WriteLine("valueA + 500 = " + resultA); // 1500
Console.WriteLine("valueB + 500 = " + resultB); // (空白: null)
// --- null 合体演算子(??)でデフォルト値を設定します ---
Console.WriteLine("\n=== null 合体演算子(??) ===");
int actualB = valueB ?? 0; // valueB が null なら 0 を使います。
Console.WriteLine("valueB ?? 0 = " + actualB); // 0
int actualA = valueA ?? 0; // valueA は null でないのでそのまま使われます。
Console.WriteLine("valueA ?? 0 = " + actualA); // 1000
// --- Nullable型の比較 ---
Console.WriteLine("\n=== Nullable型の比較 ===");
// null との比較は == null か is null を使います。
Console.WriteLine("valueB == null: " + (valueB == null)); // True
Console.WriteLine("valueB is null: " + (valueB is null)); // True
Console.WriteLine("valueA == null: " + (valueA == null)); // False
// null に対する > / < などは常に false を返します。
Console.WriteLine("null > 0: " + (valueB > 0)); // False
Console.WriteLine("null < 0: " + (valueB < 0)); // False
Console.WriteLine("null == 0: " + (valueB == 0)); // False(null は 0 と等しくありません)。
// --- ビット演算子の応用: フラグ管理 ---
Console.WriteLine("\n=== ビット演算子によるフラグ管理 ===");
// 状態フラグをビットで管理する例です。
const int FLAG_A = 0b0001;
const int FLAG_B = 0b0010;
const int FLAG_C = 0b0100;
const int FLAG_D = 0b1000;
int flags = FLAG_A | FLAG_B | FLAG_C; // 複数フラグを OR で設定します。
Console.WriteLine("フラグ値: " + flags); // 7(0111)
// フラグが立っているか AND で確認します。
bool hasA = (flags & FLAG_A) != 0;
bool hasD = (flags & FLAG_D) != 0;
Console.WriteLine("FLAG_A: " + hasA); // True
Console.WriteLine("FLAG_D: " + hasD); // False
// フラグを追加するには OR を使います。
flags |= FLAG_D;
Console.WriteLine("FLAG_D追加後のフラグ値: " + flags); // 15(1111)
// フラグを削除するには AND NOT を使います。
flags &= ~FLAG_B;
Console.WriteLine("FLAG_B削除後のフラグ値: " + flags); // 13(1101)
}
}
コンパイルして実行すると次のようになります。
dotnet script NullableOperators.cs === Nullable型と算術演算子 === valueA + 500 = 1500 valueB + 500 = === null 合体演算子(??) === valueB ?? 0 = 0 valueA ?? 0 = 1000 === Nullable型の比較 === valueB == null: True valueB is null: True valueA == null: False null > 0: False null < 0: False null == 0: False === ビット演算子によるフラグ管理 === フラグ値: 7 FLAG_A: True FLAG_D: False FLAG_D追加後のフラグ値: 15 FLAG_B削除後のフラグ値: 13
よくあるミス
整数除算で小数を期待する
int / int の結果は int です。小数部は切り捨てられ、9 / 2 は 4 になります(4.5 ではありません)。浮動小数点数の結果が必要な場合は、少なくとも一方を double にキャストしてください。
int a = 9; int b = 2; int wrong = a / b; Console.WriteLine(wrong); // 4(小数部が切り捨てられます) double correct = (double)a / b; Console.WriteLine(correct); // 4.5
文字列 + 数値の連結で加算にならない
"結果: " + a + b と書くと、a と b は文字列に変換されてから連結されるため、数値の加算にはなりません。数値を先に加算したい場合は括弧で囲みます。
int x = 100;
int y = 200;
Console.WriteLine("合計: " + x + y); // 合計: 100200(文字列連結)
Console.WriteLine("合計: " + (x + y)); // 合計: 300(数値の加算)
概要
『C#』の演算子で特に注意が必要なのは整数除算です。int 同士の / は結果も int になり、小数部が無条件に切り捨てられます。9 / 2 は 4.5 ではなく 4 です。浮動小数点数の結果が必要な場合は (double)a / b のように明示的にキャストしてください。
string の + は文字列連結として機能します。Console.WriteLine("合計: " + a + b) と書くと数値の加算ではなく文字列連結が行われるため、数値を先に加算したい場合は "合計: " + (a + b) のように括弧で囲む必要があります。
&& と || の短絡評価を活用することで、null チェックを先に行い安全にプロパティやメソッドへアクセスするコードが書けます。なお &・|(ビット演算子)は bool 型にも使えますが、短絡評価が行われないため通常の条件分岐では &&・|| を使ってください。
Nullable 型(int? など)に対する算術演算は null が伝播します。null ?? 0 のように null 合体演算子でデフォルト値を与えるか、HasValue プロパティで null チェックをしてから計算してください。Nullable 型の詳細は『Nullable 型』を参照してください。null 合体演算子については『null 合体演算子(??)』も参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。