演算子(C#)
算術演算子・比較演算子・論理演算子をまとめて解説します。『C#』では演算子の種類が豊富で、整数除算の挙動や文字列への + 演算子の挙動など、他の言語と異なる点があります。Nullable 型との組み合わせやビット演算子についても確認しておきましょう。
算術演算子
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
+ | 加算。文字列の場合は連結。 | 9000 + 1000 | 10000 |
- | 減算。 | 9000 - 500 | 8500 |
* | 乗算。 | 9000 * 2 | 18000 |
/ | 除算。整数同士の場合は結果も整数(小数部切り捨て)。 | 9000 / 4 | 2250 |
% | 剰余(余り)。 | 9000 % 7 | 3 |
++ | インクリメント。値を1増やします。 | level++ | level + 1 |
-- | デクリメント。値を1減らします。 | level-- | level - 1 |
整数同士の / は結果も整数になります。9000 / 4 の結果は 2250 であり、2250.0 にはなりません。浮動小数点数の結果が必要な場合は、どちらか一方を double や float にキャストしてください(例: (double)9000 / 4)。
string に対する + 演算子は文字列連結になります。数値と文字列を + でつなぐと、数値が自動的に文字列に変換されて連結されます(例: "戦闘力: " + 9000 → "戦闘力: 9000")。
比較演算子
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
== | 等しい。 | power == 9000 | true / false |
!= | 等しくない。 | power != 0 | true / false |
> | より大きい。 | power > 9000 | true / false |
>= | 以上。 | power >= 9000 | true / false |
< | より小さい。 | power < 9000 | true / false |
<= | 以下。 | power <= 9000 | 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; // result は null になります。
// 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 gokuPower = 9000; // 孫悟空の基本戦闘力です。
int boostPower = 1500; // 変身による強化値です。
Console.WriteLine("=== 算術演算子の基本 ===");
Console.WriteLine("加算(+): " + (gokuPower + boostPower)); // 10500
Console.WriteLine("減算(-): " + (gokuPower - boostPower)); // 7500
Console.WriteLine("乗算(*): " + (gokuPower * 2)); // 18000
Console.WriteLine("剰余(%): " + (gokuPower % 7)); // 9000 を 7 で割った余りです。
// --- 整数除算の挙動 ---
// 整数同士の割り算は小数部が切り捨てられます。
Console.WriteLine("\n=== 整数除算 ===");
int intDiv = gokuPower / 4; // 整数除算: 2250(小数部なし)。
double doubleDiv = (double)gokuPower / 4; // キャストで浮動小数点除算: 2250.0。
Console.WriteLine("int / int: " + intDiv); // 2250
Console.WriteLine("double / int: " + doubleDiv); // 2250
// 割り切れない場合に違いが現れます。
int intRemainder = 9000 / 7; // 1285(0.71... が切り捨て)。
double doubleRemainder = (double)9000 / 7; // 1285.7142...
Console.WriteLine("9000 / 7 (int): " + intRemainder); // 1285
Console.WriteLine("9000 / 7 (double): " + doubleRemainder); // 1285.71428571429
// --- インクリメント・デクリメント ---
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++; // b には加算前の値(5)が入ります。aは6になります。
Console.WriteLine("a = " + a + ", b = " + b); // a=6, b=5
int c = 5;
int d = ++c; // d には加算後の値(6)が入ります。cも6になります。
Console.WriteLine("c = " + c + ", d = " + d); // c=6, d=6
// --- 文字列への + 演算子 ---
// 文字列と数値を + でつなぐと、数値は自動的に文字列に変換されます。
Console.WriteLine("\n=== 文字列への + 演算子 ===");
string name = "孫悟空";
int power = 9000;
string msg = name + "の戦闘力は" + power + "です。"; // 数値が文字列に変換されます。
Console.WriteLine(msg); // 孫悟空の戦闘力は9000です。
// 数値同士を先に足してから連結することで意図通りの結果になります。
Console.WriteLine("合計: " + (power + 1000)); // 合計: 10000(数値の加算)。
Console.WriteLine("合計: " + power + 1000); // 合計: 90001000(文字列連結)。
}
}
dotnet script ArithmeticOperators.cs === 算術演算子の基本 === 加算(+): 10500 減算(-): 7500 乗算(*): 18000 剰余(%): 6 === 整数除算 === int / int: 2250 double / int: 2250 9000 / 7 (int): 1285 9000 / 7 (double): 1285.71428571429 === インクリメント・デクリメント === 初期 level: 1 level++ 後: 2 ++level 後: 3 level-- 後: 2 a = 6, b = 5 c = 6, d = 6 === 文字列への + 演算子 === 孫悟空の戦闘力は9000です。 合計: 10000 合計: 90001000
ComparisonLogicalOperators.cs
using System;
class ComparisonLogicalOperators {
static void Main() {
// --- 比較演算子 ---
int gokuPower = 9000; // 孫悟空の戦闘力です。
int vegetaPower = 8500; // ベジータの戦闘力です。
int friezaPower = 12000; // フリーザの戦闘力です。
Console.WriteLine("=== 比較演算子 ===");
Console.WriteLine("goku == vegeta: " + (gokuPower == vegetaPower)); // False
Console.WriteLine("goku != vegeta: " + (gokuPower != vegetaPower)); // True
Console.WriteLine("goku > vegeta: " + (gokuPower > vegetaPower)); // True
Console.WriteLine("goku >= frieza: " + (gokuPower >= friezaPower)); // False
Console.WriteLine("goku < frieza: " + (gokuPower < friezaPower)); // True
Console.WriteLine("goku <= frieza: " + (gokuPower <= friezaPower)); // True
// --- string の == は値(内容)で比較されます ---
Console.WriteLine("\n=== string の比較 ===");
string name1 = "孫悟空";
string name2 = "孫悟空"; // 同じ内容の別の string 変数です。
string name3 = "ベジータ";
Console.WriteLine("name1 == name2: " + (name1 == name2)); // True(内容が同じ)。
Console.WriteLine("name1 == name3: " + (name1 == name3)); // False(内容が異なる)。
// --- 論理演算子 ---
Console.WriteLine("\n=== 論理演算子 ===");
bool isSaiyan = true; // サイヤ人かどうかです。
bool hasKaioken = true; // 界王拳を使えるかどうかです。
bool hasTail = false; // 尻尾があるかどうかです。
// &&(AND): 両方がtrueのときtrueになります。
bool canTransformOzaru = isSaiyan && hasTail;
Console.WriteLine("大猿変身可能(サイヤ人 && 尻尾あり): " + canTransformOzaru); // False
// ||(OR): どちらかがtrueのときtrueになります。
bool isStrong = isSaiyan || hasKaioken;
Console.WriteLine("強力(サイヤ人 || 界王拳): " + isStrong); // True
// !(NOT): 値を反転させます。
bool isWeak = !isSaiyan;
Console.WriteLine("弱い(!サイヤ人): " + isWeak); // False
// --- 複合条件 ---
Console.WriteLine("\n=== 複合条件 ===");
// 孫悟空がフリーザに勝てるかの判定(複合条件の例)。
int threshold = 10000; // 勝利に必要な戦闘力の閾値です。
bool gokuWins = isSaiyan && (gokuPower >= threshold || hasKaioken);
Console.WriteLine("孫悟空勝利条件(サイヤ人 && (戦闘力十分 || 界王拳)): " + gokuWins); // True
// --- 短絡評価(ショートサーキット評価)---
// &&: 左辺がfalseなら右辺は評価されません。
// ||: 左辺がtrueなら右辺は評価されません。
Console.WriteLine("\n=== 短絡評価 ===");
// null チェックと組み合わせた安全なアクセスパターンです。
string heroName = "孫悟空";
bool hasLongName = heroName != null && heroName.Length > 3;
// heroName が null なら heroName.Length は評価されないためNullReferenceExceptionが起きません。
Console.WriteLine("名前が3文字より長い: " + hasLongName); // True(4文字)。
// null の場合は短絡評価で右辺をスキップします。
string nullName = null;
bool isNullLong = nullName != null && nullName.Length > 3;
Console.WriteLine("null の名前が3文字より長い: " + isNullLong); // False(右辺は評価されない)。
}
}
dotnet script ComparisonLogicalOperators.cs === 比較演算子 === goku == vegeta: False goku != vegeta: True goku > vegeta: True goku >= frieza: False goku < frieza: True goku <= frieza: 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? gokuHp = 1000; // 孫悟空のHPです(値あり)。
int? cellHp = null; // セルのHPです(未確認のためnull)。
Console.WriteLine("=== Nullable型と算術演算子 ===");
// Nullable型に算術演算子を使うと null が伝播します。
int? gokuResult = gokuHp + 500; // 値がある場合は通常通り計算されます。
int? cellResult = cellHp + 500; // null に対する演算は null になります。
Console.WriteLine("gokuHp + 500 = " + gokuResult); // 1500
Console.WriteLine("cellHp + 500 = " + cellResult); // (空白: null)
// --- null 合体演算子(??)でデフォルト値を設定します ---
Console.WriteLine("\n=== null 合体演算子(??) ===");
int actualCellHp = cellHp ?? 0; // cellHp が null なら 0 を使います。
Console.WriteLine("cellHp ?? 0 = " + actualCellHp); // 0
int actualGokuHp = gokuHp ?? 0; // gokuHp は null でないのでそのまま使われます。
Console.WriteLine("gokuHp ?? 0 = " + actualGokuHp); // 1000
// --- Nullable型の比較 ---
Console.WriteLine("\n=== Nullable型の比較 ===");
// null との比較は == null か is null を使います。
Console.WriteLine("cellHp == null: " + (cellHp == null)); // True
Console.WriteLine("cellHp is null: " + (cellHp is null)); // True
Console.WriteLine("gokuHp == null: " + (gokuHp == null)); // False
// null に対する > / < などは常に false を返します。
Console.WriteLine("null > 0: " + (cellHp > 0)); // False
Console.WriteLine("null < 0: " + (cellHp < 0)); // False
Console.WriteLine("null == 0: " + (cellHp == 0)); // False(null は 0 と等しくありません)。
// --- ビット演算子の応用: フラグ管理 ---
Console.WriteLine("\n=== ビット演算子によるフラグ管理 ===");
// 能力フラグをビットで管理する例です。
const int FLAG_SAIYAN = 0b0001; // サイヤ人フラグです。
const int FLAG_KAIOKEN = 0b0010; // 界王拳フラグです。
const int FLAG_SSJ = 0b0100; // 超サイヤ人フラグです。
const int FLAG_SSJ2 = 0b1000; // 超サイヤ人2フラグです。
int gokuFlags = FLAG_SAIYAN | FLAG_KAIOKEN | FLAG_SSJ; // 複数フラグを OR で設定します。
Console.WriteLine("孫悟空のフラグ値: " + gokuFlags); // 7(0111)
// フラグが立っているか AND で確認します。
bool isSaiyan = (gokuFlags & FLAG_SAIYAN) != 0;
bool hasSsj2 = (gokuFlags & FLAG_SSJ2) != 0;
Console.WriteLine("サイヤ人フラグ: " + isSaiyan); // True
Console.WriteLine("超サイヤ人2フラグ: " + hasSsj2); // False
// フラグを追加するには OR を使います。
gokuFlags |= FLAG_SSJ2;
Console.WriteLine("SSJ2追加後のフラグ値: " + gokuFlags); // 15(1111)
// フラグを削除するには AND NOT を使います。
gokuFlags &= ~FLAG_KAIOKEN;
Console.WriteLine("界王拳削除後のフラグ値: " + gokuFlags); // 13(1101)
}
}
dotnet script NullableOperators.cs === Nullable型と算術演算子 === gokuHp + 500 = 1500 cellHp + 500 = === null 合体演算子(??) === cellHp ?? 0 = 0 gokuHp ?? 0 = 1000 === Nullable型の比較 === cellHp == null: True cellHp is null: True gokuHp == null: False null > 0: False null < 0: False null == 0: False === ビット演算子によるフラグ管理 === 孫悟空のフラグ値: 7 サイヤ人フラグ: True 超サイヤ人2フラグ: False SSJ2追加後のフラグ値: 15 界王拳削除後のフラグ値: 13
概要
『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 合体演算子(??)』も参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。