C# operators完全ガイド|演算子の種類・優先順位・使い方を初心者向けに解説

はじめに

C#でプログラムを書くとき、変数や値を計算したり、比較したり、条件によって処理を分けたりする場面で必ず登場するのが「演算子」です。英語では「C# operators」と呼ばれ、+===&&??.[]=>など、非常に多くの種類があります。

演算子は一見すると記号の集まりに見えますが、意味を理解するとコードの読み書きが一気に楽になります。たとえば、a + b * cのような式では、どの演算が先に実行されるかを知らないと、意図しない結果になることがあります。

この記事では、C# operatorsの種類、使い方、優先順位、null関連の演算子、型変換、ビット演算、ラムダ式、演算子オーバーロードまで、初心者にもわかりやすく解説します。

1. C# operators(演算子)とは?初心者向けの基本

1-1. C#における演算子の役割

C#の演算子は、値に対して何らかの操作を行うための記号やキーワードです。たとえば、+は加算、=は代入、==は等しいかどうかの比較、&&は複数条件のAND判定に使います。

C#
int a = 10;
int b = 3;

int sum = a + b; // 加算
bool result = a > b; // 比較

C#には算術、比較、論理、ビット演算、null処理、型チェック、メンバーアクセスなど、さまざまな演算子が用意されています。公式リファレンスでも、C# operatorsは複雑な式を作る基本要素として説明されています。

1-2. 演算子・オペランド・式の関係

演算子を理解するには、「オペランド」と「式」もセットで覚えるとわかりやすくなります。

C#
int result = 10 + 5;

この例では、+が演算子、105がオペランドです。そして10 + 5全体が式です。式は評価されると結果を返します。この場合、結果は15です。

演算子には、1つのオペランドに作用する単項演算子、2つのオペランドに作用する二項演算子、3つの要素を使う条件演算子があります。

C#
int x = 10;

int positive = +x; // 単項演算子
int total = x + 5; // 二項演算子
string text = x > 0 ? "正" : "負"; // 条件演算子

1-3. C# operatorsを学ぶと何ができるようになるか

C# operatorsを理解すると、次のようなコードが自然に書けるようになります。

C#
if (user != null && user.Age >= 20)
{
Console.WriteLine($"{user.Name}さんは成人です");
}

この短いコードにも、!=&&.>=$""内の式など、複数の要素が含まれています。演算子を理解すれば、条件分岐、ループ、配列操作、LINQ、null安全な処理、オブジェクト指向のコードが読みやすくなります。

1-4. 初心者がつまずきやすいポイント

初心者が特につまずきやすいのは、次のような違いです。

C#
x = 10;      // 代入
x == 10; // 比較

a && b; // 条件付きAND
a & b; // AND。ただしboolでは両方評価、整数ではビット演算

name ?? "未設定"; // nullなら代替値
name?.Length; // nullでなければLengthにアクセス

同じように見える記号でも、用途や評価方法が異なります。最初はすべてを暗記しようとせず、「計算」「比較」「条件」「null対策」「型変換」という用途別に覚えるのがおすすめです。

2. C# operatorsの種類一覧

2-1. 算術演算子

算術演算子は、数値の計算に使います。

演算子意味
+加算a + b
-減算a - b
*乗算a * b
/除算a / b
%剰余a % b
++1増やすi++
--1減らすi--

C#の算術演算子は、主に数値型のオペランドに対して使われます。+は数値の加算だけでなく、文字列結合にも使われます。

2-2. 代入演算子

代入演算子は、変数に値を入れるために使います。

C#
int count = 10;
count += 5; // count = count + 5 とほぼ同じ

代表的な代入演算子は、=+=-=*=/=%=??=などです。

2-3. 比較演算子・等価演算子

比較演算子は、2つの値を比べてbool型の結果を返します。

演算子意味
==等しい
!=等しくない
<より小さい
>より大きい
<=以下
>=以上
C#
int score = 80;

bool passed = score >= 60;

2-4. 論理演算子

論理演算子は、bool型の条件を組み合わせるために使います。

C#
bool isAdult = age >= 20;
bool hasTicket = true;

if (isAdult && hasTicket)
{
Console.WriteLine("入場できます");
}

&&はAND、||はOR、!は否定です。&&||は必要な場合だけ右側を評価するため、nullチェックなどでよく使われます。

2-5. ビット演算子・シフト演算子

ビット演算子は、整数値を2進数のビット単位で扱う演算子です。

演算子意味
&ビットAND
``
^ビットXOR
~ビット反転
<<左シフト
>>右シフト
>>>符号なし右シフト

>>>は符号ビットを考慮せずに右へシフトする演算子です。C#のビット演算子とシフト演算子には、~<<>>>>>&|^が含まれます。

2-6. インクリメント・デクリメント演算子

++は値を1増やし、--は値を1減らします。

C#
int i = 0;

i++; // 1になる
i--; // 0に戻る

前置と後置で結果が変わる場合があるため、後ほど詳しく解説します。

2-7. 条件演算子

条件演算子?:は、条件によって返す値を切り替える演算子です。

C#
string result = score >= 60 ? "合格" : "不合格";

短いif文のように使えますが、複雑になりすぎる場合は通常のif文やswitch式を使ったほうが読みやすくなります。

2-8. null関連の演算子

C#ではnullを安全に扱うための演算子が多く用意されています。

演算子意味
??nullなら右側を返す
??=nullなら代入する
?.nullでなければメンバーにアクセス
?[]nullでなければ要素にアクセス
!nullではないとコンパイラに伝える
C#
string? name = null;
string displayName = name ?? "ゲスト";

????=は、左側がnullかどうかによって右側を評価するかどうかが変わります。

2-9. 型チェック・型変換に関する演算子

型チェックや型変換には、isas、キャスト、typeofsizeofnameofなどを使います。

C#
object value = "Hello";

if (value is string text)
{
Console.WriteLine(text.Length);
}

isは型の確認、asは失敗時にnullを返す型変換、キャストは明示的な型変換に使います。

2-10. メンバーアクセス・インデックス・範囲演算子

オブジェクトのプロパティやメソッドにアクセスするには.を使います。配列やリストの要素にアクセスするには[]を使います。

C#
string text = "CSharp";

Console.WriteLine(text.Length); // .
Console.WriteLine(text[0]); // []
Console.WriteLine(text[^1]); // 最後の文字
Console.WriteLine(text[1..4]); // 範囲

.[]?.?[]^..は、メンバーや要素、範囲を扱うときに使われる演算子です。

2-11. ラムダ演算子・その他の特殊な演算子

ラムダ演算子=>は、匿名関数や式形式メンバーで使います。

C#
Func<int, int> square = x => x * x;

int result = square(5); // 25

そのほか、newawaitdefaultdelegatecheckeduncheckedsizeofnameofなども、式の中で使われる重要なC# operatorsです。

3. 算術演算子の使い方

3-1. +・-・*・/・%の基本

基本的な算術演算子は、四則演算と剰余です。

C#
int a = 10;
int b = 3;

Console.WriteLine(a + b); // 13
Console.WriteLine(a - b); // 7
Console.WriteLine(a * b); // 30
Console.WriteLine(a / b); // 3
Console.WriteLine(a % b); // 1

%は割り算の余りを求める演算子です。偶数・奇数の判定でよく使います。

C#
int number = 7;

if (number % 2 == 0)
{
Console.WriteLine("偶数");
}
else
{
Console.WriteLine("奇数");
}

3-2. 整数同士の割り算で小数が切り捨てられる理由

C#では、int同士を/で割ると結果もintになります。そのため、小数部分は切り捨てられます。

C#
int a = 10;
int b = 3;

Console.WriteLine(a / b); // 3

小数まで必要な場合は、どちらか一方をdoubledecimalにします。

C#
double result = 10.0 / 3;
Console.WriteLine(result); // 3.333...

またはキャストを使います。

C#
int a = 10;
int b = 3;

double result = (double)a / b;
Console.WriteLine(result);

3-3. 文字列結合で使う+演算子

+は数値の加算だけでなく、文字列結合にも使えます。

C#
string firstName = "Taro";
string lastName = "Yamada";

string fullName = lastName + " " + firstName;
Console.WriteLine(fullName);

ただし、複数の値を埋め込む場合は、文字列補間のほうが読みやすいです。

C#
int age = 25;
string name = "Taro";

Console.WriteLine($"{name}さんは{age}歳です");

3-4. checked・uncheckedによるオーバーフロー制御

整数型には扱える範囲があります。範囲を超える計算をしたとき、オーバーフローが発生することがあります。

C#
int max = int.MaxValue;

checked
{
int result = max + 1; // オーバーフロー時に例外
}

checkedを使うと、オーバーフローを検出して例外を発生させます。uncheckedを使うと、オーバーフロー検出を行わずに処理します。

C#
int max = int.MaxValue;

unchecked
{
int result = max + 1;
Console.WriteLine(result);
}

金額、在庫数、集計処理など、数値の正確性が重要な場面ではcheckedを意識すると安全です。

3-5. 算術演算子の実践コード例

税込価格を計算する例です。

C#
decimal price = 1200m;
decimal taxRate = 0.10m;

decimal tax = price * taxRate;
decimal total = price + tax;

Console.WriteLine($"税抜価格: {price}円");
Console.WriteLine($"消費税: {tax}円");
Console.WriteLine($"税込価格: {total}円");

平均点を求める例です。

C#
int japanese = 80;
int math = 90;
int english = 70;

double average = (japanese + math + english) / 3.0;

Console.WriteLine($"平均点: {average}");

3ではなく3.0にすることで、小数を含む計算になります。

4. 代入演算子と複合代入演算子

4-1. =による基本的な代入

=は、右側の値を左側の変数に代入する演算子です。

C#
int number = 10;
string message = "Hello";

数学では=は等しいという意味ですが、C#では「右の値を左へ入れる」という意味です。等しいかどうかを調べる場合は==を使います。

C#
int x = 10;

bool result = x == 10; // true

4-2. +=・-=・*=・/=・%=の使い方

複合代入演算子を使うと、現在の値を使った更新を短く書けます。

C#
int count = 10;

count += 5; // count = count + 5
count -= 2; // count = count - 2
count *= 3; // count = count * 3
count /= 2; // count = count / 2
count %= 4; // count = count % 4

スコア加算やカウンター更新でよく使います。

C#
int score = 0;

score += 10;
score += 20;

Console.WriteLine(score); // 30

4-3. ??=によるnull合体代入

??=は、左側がnullの場合だけ右側の値を代入します。

C#
List<string>? names = null;

names ??= new List<string>();
names.Add("Alice");

これは次のコードを短くしたものです。

C#
if (names == null)
{
names = new List<string>();
}

??=は、コレクションや設定値を必要になったタイミングで初期化するときに便利です。

4-4. 代入式の戻り値と連続代入

C#では、代入式自体も値を返します。そのため、連続代入ができます。

C#
int a;
int b;
int c;

a = b = c = 10;

この場合、右から順に評価され、abcすべてに10が入ります。

ただし、読みやすさを考えると、連続代入は単純な初期化に限定するのがおすすめです。

4-5. 代入演算子でよくあるミス

最も多いミスは、===の混同です。

C#
int x = 10;

// 正しい
if (x == 10)
{
Console.WriteLine("10です");
}

C#では、if (x = 10)のようにintを条件式として使うことはできないため、多くの場合はコンパイルエラーになります。ただし、bool変数では意図しない代入が紛れ込む可能性があります。

C#
bool isEnabled = false;

if (isEnabled = true)
{
Console.WriteLine("常に実行される");
}

このようなコードは避け、比較が必要なら==を使うか、boolならそのまま書きます。

C#
if (isEnabled)
{
Console.WriteLine("有効です");
}

5. 比較演算子・論理演算子の使い方

5-1. ==・!=・<・>・<=・>=の基本

比較演算子は、条件分岐やループでよく使います。

C#
int age = 18;

Console.WriteLine(age == 18); // true
Console.WriteLine(age != 20); // true
Console.WriteLine(age < 20); // true
Console.WriteLine(age >= 18); // true

文字列の比較にも==を使えます。

C#
string role = "admin";

if (role == "admin")
{
Console.WriteLine("管理者です");
}

ただし、大文字・小文字を区別しない比較や文化圏を考慮した比較が必要な場合は、StringComparisonを使うと安全です。

C#
string input = "Admin";

bool isAdmin = string.Equals(input, "admin", StringComparison.OrdinalIgnoreCase);

5-2. &&・||・!による条件式の書き方

&&は「かつ」、||は「または」、!は「ではない」を表します。

C#
int age = 25;
bool hasLicense = true;

if (age >= 18 && hasLicense)
{
Console.WriteLine("運転できます");
}
C#
bool isWeekend = true;
bool isHoliday = false;

if (isWeekend || isHoliday)
{
Console.WriteLine("休みです");
}
C#
bool isDeleted = false;

if (!isDeleted)
{
Console.WriteLine("表示します");
}

5-3. &&と&、||と|の違い

&&||は短絡評価を行います。つまり、結果が決まった時点で右側を評価しません。

C#
User? user = null;

if (user != null && user.Age >= 20)
{
Console.WriteLine("成人です");
}

この例では、user != nullfalseなら、user.Ageは評価されません。そのため、NullReferenceExceptionを防げます。

一方、&|をboolに使うと、両方のオペランドが評価されます。

C#
if (user != null & user.Age >= 20)
{
Console.WriteLine("成人です");
}

この場合、userがnullでも右側が評価されるため、例外になる可能性があります。条件式では基本的に&&||を使いましょう。

5-4. if文・while文での活用例

if文では、比較演算子と論理演算子を組み合わせます。

C#
int score = 85;

if (score >= 80)
{
Console.WriteLine("優秀");
}
else if (score >= 60)
{
Console.WriteLine("合格");
}
else
{
Console.WriteLine("不合格");
}

while文では、条件がtrueの間だけ繰り返します。

C#
int count = 0;

while (count < 5)
{
Console.WriteLine(count);
count++;
}

5-5. bool型と条件式でよくあるエラー

C#のif文やwhile文の条件には、bool型の式が必要です。

C#
int count = 1;

// エラー
// if (count)
// {
// }

CやJavaScriptのように、0ならfalse、1ならtrueという書き方はできません。明示的に比較します。

C#
if (count > 0)
{
Console.WriteLine("1以上です");
}

この性質により、C#では条件式の意図が明確になりやすいです。

6. null関連の演算子を理解する

6-1. null合体演算子??の使い方

??は、左側がnullでなければ左側を返し、nullなら右側を返します。

C#
string? name = null;

string displayName = name ?? "ゲスト";
Console.WriteLine(displayName); // ゲスト

設定値や入力値にデフォルト値を与えるときに便利です。

C#
string? environment = Environment.GetEnvironmentVariable("APP_ENV");
string current = environment ?? "Development";

6-2. null合体代入演算子??=の使い方

??=は、変数がnullの場合だけ代入します。

C#
List<int>? numbers = null;

numbers ??= new List<int>();
numbers.Add(10);

初期化済みなら上書きしないため、既存の値を保持したいときに使えます。

C#
string? title = "既存タイトル";

title ??= "新しいタイトル";

Console.WriteLine(title); // 既存タイトル

6-3. null条件演算子?.・?[]の使い方

?.は、左側がnullでない場合だけメンバーにアクセスします。

C#
User? user = null;

int? length = user?.Name?.Length;

?[]は、左側がnullでない場合だけインデックスアクセスします。

C#
string[]? names = null;

string? first = names?[0];

ただし、配列自体がnullでない場合でも、インデックスが範囲外なら例外は発生します。?[]は「nullチェック」を助けるものであり、「範囲チェック」を省略できるものではありません。

6-4. null許容型と?の関係

?は、null許容型にも使われます。

C#
int? age = null;
string? name = null;

int?は、intまたはnullを持てる型です。string?は、nullになる可能性がある参照型として扱われます。

C#
int? score = null;

int value = score ?? 0;

null許容型を使うと、値が存在しない状態を明示できます。

6-5. null免除演算子!の注意点

後置の!は、null免除演算子です。コンパイラに対して「これはnullではない」と伝えます。

C#
string? name = GetName();

Console.WriteLine(name!.Length);

ただし、実行時に本当にnullだった場合はNullReferenceExceptionが発生します。!はnullチェックを実行する演算子ではありません。安易に使うと、null安全性を壊してしまいます。

6-6. NullReferenceExceptionを防ぐ書き方

null関連の演算子を組み合わせると、安全なコードを書きやすくなります。

C#
User? user = GetUser();

string displayName = user?.Name ?? "ゲスト";
Console.WriteLine(displayName);

メソッド呼び出しでも使えます。

C#
user?.SendEmail();

コレクション初期化では??=が便利です。

C#
private List<string>? _logs;

void AddLog(string message)
{
_logs ??= new List<string>();
_logs.Add(message);
}

nullチェック、?.????=を適切に使うと、NullReferenceExceptionを大幅に減らせます。

7. 型チェック・型変換に関する演算子

7-1. is演算子の基本

is演算子は、値が特定の型かどうかを調べます。

C#
object value = "Hello";

if (value is string)
{
Console.WriteLine("文字列です");
}

C#では、isと変数宣言を組み合わせる書き方がよく使われます。

C#
object value = "Hello";

if (value is string text)
{
Console.WriteLine(text.Length);
}

この書き方では、型チェックとキャストを同時に行えます。

7-2. as演算子による安全な型変換

as演算子は、変換できる場合は指定した型に変換し、できない場合はnullを返します。

C#
object value = "Hello";

string? text = value as string;

if (text != null)
{
Console.WriteLine(text.Length);
}

asは例外を投げないため、安全に見えますが、変換後にnullチェックが必要です。最近のC#では、isによるパターンマッチングのほうが読みやすい場面も多いです。

C#
if (value is string text)
{
Console.WriteLine(text.Length);
}

7-3. キャスト演算子の使い方

キャストは、値を明示的に別の型へ変換します。

C#
double d = 123.45;
int i = (int)d;

Console.WriteLine(i); // 123

参照型でも使えます。

C#
object value = "Hello";

string text = (string)value;
Console.WriteLine(text.Length);

ただし、変換できない場合は例外が発生します。

C#
object value = 123;

// InvalidCastException
// string text = (string)value;

安全性を重視するなら、isasを使いましょう。

7-4. typeof・sizeof・nameofの使い方

typeofは型情報を取得します。

C#
Type type = typeof(string);
Console.WriteLine(type.FullName);

nameofは、変数名、型名、メンバー名を文字列として取得します。

C#
string userName = "Alice";

Console.WriteLine(nameof(userName)); // userName

例外メッセージやログでよく使います。

C#
void SetName(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
}

sizeofは、値型のサイズを取得します。通常のアプリ開発では使用頻度は高くありませんが、低レベルな処理で使われることがあります。

C#
Console.WriteLine(sizeof(int)); // 4

7-5. パターンマッチングとis演算子

isはパターンマッチングと組み合わせると強力です。

C#
object value = 42;

if (value is int number and > 0)
{
Console.WriteLine($"正の整数: {number}");
}

型だけでなく、値の条件も同時に表現できます。

C#
static string GetLabel(object value)
{
return value switch
{
int n when n > 0 => "正の整数",
int n when n < 0 => "負の整数",
string s => $"文字列: {s}",
null => "null",
_ => "その他"
};
}

7-6. 型変換で発生しやすい例外

型変換では、主に次のような例外に注意します。

例外発生例
InvalidCastException不正なキャスト
FormatException文字列の形式が不正
OverflowException数値範囲を超える変換
C#
string text = "abc";

// FormatException
// int number = int.Parse(text);

安全に変換したい場合は、TryParseを使います。

C#
string text = "123";

if (int.TryParse(text, out int number))
{
Console.WriteLine(number);
}
else
{
Console.WriteLine("数値ではありません");
}

8. ビット演算子・シフト演算子

8-1. &・|・^・~の基本

ビット演算子は、整数を2進数として扱います。

C#
int a = 0b_1100;
int b = 0b_1010;

Console.WriteLine(Convert.ToString(a & b, 2)); // 1000
Console.WriteLine(Convert.ToString(a | b, 2)); // 1110
Console.WriteLine(Convert.ToString(a ^ b, 2)); // 0110

~はビットを反転します。

C#
int x = 0b_0001;
int y = ~x;

ビット演算は、フラグ管理、権限管理、低レベル処理、パフォーマンスを重視する場面などで使われます。

8-2. <<・>>・>>>の使い方

<<は左シフト、>>は右シフトです。

C#
int x = 4;        // 0100
int left = x << 1; // 1000 = 8
int right = x >> 1; // 0010 = 2

>>>は符号なし右シフトです。

C#
int value = -8;
int shifted = value >>> 1;

符号付き整数を右シフトするとき、>>>>>では結果が異なる場合があります。通常の業務アプリでは頻繁に使いませんが、ビット列そのものを扱う処理では重要です。

8-3. フラグ管理でのビット演算

ビット演算は、複数の状態を1つの値で管理するときに使えます。

C#
[Flags]
enum Permission
{
None = 0,
Read = 1,
Write = 2,
Execute = 4
}

複数の権限を組み合わせるには|を使います。

C#
Permission permission = Permission.Read | Permission.Write;

特定の権限を持っているか確認するには&を使います。

C#
bool canRead = (permission & Permission.Read) == Permission.Read;

フラグを外すには、&~を組み合わせます。

C#
permission &= ~Permission.Write;

8-4. ビット演算を使う場面

ビット演算は、次のような場面で使われます。

用途
フラグ管理権限、設定値、状態
低レベル処理通信、ファイルフォーマット
画像処理色情報の操作
パフォーマンス重視の処理軽量な状態管理
アルゴリズムビットマスク、集合表現

初心者のうちは、まず[Flags] enumでの使い方を理解すれば十分です。

8-5. 初心者が混同しやすい論理演算子との違い

&|は、boolに使う場合と整数に使う場合で意味が変わります。

C#
bool a = true;
bool b = false;

Console.WriteLine(a & b); // 論理AND
Console.WriteLine(a | b); // 論理OR
C#
int x = 0b_1100;
int y = 0b_1010;

Console.WriteLine(x & y); // ビットAND
Console.WriteLine(x | y); // ビットOR

条件式では、通常&&||を使います。ビット単位の操作をしたいときだけ&|^を使うと覚えるとよいでしょう。

9. インクリメント・デクリメント演算子

9-1. ++・--の基本

++は値を1増やし、--は値を1減らします。

C#
int count = 0;

count++;
Console.WriteLine(count); // 1

count--;
Console.WriteLine(count); // 0

カウンターやループでよく使います。

9-2. 前置演算子と後置演算子の違い

++iは、値を増やしてから式の結果として使います。i++は、現在の値を式の結果として使ってから増やします。

C#
int i = 1;

int a = ++i; // iを2にしてからaに代入
Console.WriteLine(a); // 2
Console.WriteLine(i); // 2
C#
int i = 1;

int a = i++; // aに1を代入してからiを2にする
Console.WriteLine(a); // 1
Console.WriteLine(i); // 2

9-3. for文での使い方

for文では、カウンター更新によく使われます。

C#
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}

この場合、i++の戻り値を使っていないため、++iでもほぼ同じように動作します。

C#
for (int i = 0; i < 5; ++i)
{
Console.WriteLine(i);
}

C#では、単純なループならどちらを使っても大きな違いはありません。チームのコーディング規約に合わせるのがよいでしょう。

9-4. 副作用による読みづらいコードの注意点

インクリメント演算子は値を変更するため、副作用があります。複雑な式の中で使うと、読みづらくなります。

C#
int i = 0;
int result = i++ + ++i;

このようなコードは避けましょう。意図を明確にするなら、処理を分けます。

C#
int i = 0;

int first = i;
i++;

i++;
int second = i;

int result = first + second;

読みやすいコードは、バグを防ぎます。

9-5. 実行結果で理解する++iとi++の違い

次のコードを見ると、違いがはっきりわかります。

C#
int i = 5;

Console.WriteLine(i++); // 5
Console.WriteLine(i); // 6
C#
int i = 5;

Console.WriteLine(++i); // 6
Console.WriteLine(i); // 6

単独で使う場合はどちらも結果的に1増えますが、式の中で使う場合は「増やすタイミング」が違います。

10. 条件演算子・ラムダ演算子・その他の演算子

10-1. 条件演算子?:の使い方

条件演算子?:は、条件によって返す値を変えます。

C#
int score = 75;

string result = score >= 60 ? "合格" : "不合格";
Console.WriteLine(result);

基本形は次のとおりです。

C#
条件 ? trueの場合の値 : falseの場合の値

値を返す式なので、変数への代入や戻り値で使えます。

C#
static string GetResult(int score)
{
return score >= 60 ? "合格" : "不合格";
}

10-2. switch式との使い分け

条件が2つだけなら?:が便利です。

C#
string label = age >= 20 ? "成人" : "未成年";

条件が複数ある場合は、switch式のほうが読みやすくなります。

C#
string grade = score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
>= 60 => "D",
_ => "F"
};

?:をネストしすぎると読みにくくなるため、分岐が増えたらswitch式を検討しましょう。

10-3. ラムダ演算子=>の基本

ラムダ演算子=>は、匿名関数を定義するために使います。

C#
Func<int, int> square = x => x * x;

Console.WriteLine(square(4)); // 16

LINQでも頻繁に使います。

C#
List<int> numbers = new() { 1, 2, 3, 4, 5 };

var evenNumbers = numbers.Where(x => x % 2 == 0);

左側が引数、右側が処理内容です。

C#
x => x * 2

複数行の処理を書く場合は、ブロックを使います。

C#
Func<int, int> doubleValue = x =>
{
int result = x * 2;
return result;
};

10-4. メンバーアクセス演算子.の使い方

.は、オブジェクトのプロパティやメソッドにアクセスするときに使います。

C#
string text = "Hello";

Console.WriteLine(text.Length);
Console.WriteLine(text.ToUpper());

名前空間や静的メンバーへのアクセスにも使います。

C#
double pi = Math.PI;
Console.WriteLine(Math.Sqrt(16));

C#のコードでは非常に頻繁に登場する演算子です。

10-5. インデックス演算子[]の使い方

[]は、配列やList、文字列などの要素にアクセスします。

C#
int[] numbers = { 10, 20, 30 };

Console.WriteLine(numbers[0]); // 10

Listでも使えます。

C#
List<string> names = new() { "Alice", "Bob" };

Console.WriteLine(names[1]); // Bob

文字列でも文字を取り出せます。

C#
string text = "CSharp";

Console.WriteLine(text[0]); // C

インデックスは0から始まります。範囲外のインデックスを指定すると例外が発生します。

10-6. インデックス^と範囲..の使い方

^は末尾から数えたインデックスを表します。

C#
int[] numbers = { 10, 20, 30, 40 };

Console.WriteLine(numbers[^1]); // 40
Console.WriteLine(numbers[^2]); // 30

..は範囲を表します。

C#
int[] numbers = { 10, 20, 30, 40, 50 };

int[] middle = numbers[1..4]; // 20, 30, 40

文字列にも使えます。

C#
string text = "CSharp";

Console.WriteLine(text[1..4]); // Sha
Console.WriteLine(text[..2]); // CS
Console.WriteLine(text[2..]); // harp

10-7. await・new・default・delegateなどの式で使う演算子

newはオブジェクトを生成します。

C#
var list = new List<string>();

awaitは非同期処理の完了を待ちます。

C#
string content = await httpClient.GetStringAsync(url);

defaultは型の既定値を取得します。

C#
int number = default;       // 0
string? text = default; // null

delegateは匿名メソッドを作るときに使えます。

C#
Func<int, int> square = delegate (int x)
{
return x * x;
};

最近のC#ではラムダ式を使うことが多いですが、既存コードではdelegateを見ることもあります。

11. C# operatorsの優先順位と結合規則

11-1. 演算子の優先順位とは

演算子の優先順位とは、複数の演算子が同じ式にあるとき、どの演算を先に行うかを決めるルールです。

C#
int result = 2 + 3 * 4;
Console.WriteLine(result); // 14

+より*のほうが優先順位が高いため、3 * 4が先に計算されます。C#では演算子の優先順位によって式の評価順が決まりますが、丸かっこで評価順を変更できます。

11-2. 結合規則とは

結合規則とは、同じ優先順位の演算子が並んだとき、左から評価するか右から評価するかを決めるルールです。

C#
int result = 10 - 3 - 2;

-は左結合なので、次のように評価されます。

C#
(10 - 3) - 2

結果は5です。

代入演算子は右結合です。

C#
a = b = c = 10;

これは次のように評価されます。

C#
a = (b = (c = 10));

11-3. 優先順位が高い演算子から低い演算子まで一覧

代表的な優先順位を高い順に並べると、次のようになります。

優先順位演算子の例分類
x.y, x[i], x++, new, typeofプライマリ
+x, -x, !x, ~x, ++x, (T)x, await単項
..範囲
*, /, %乗算系
+, -加算系
<<, >>, >>>シフト
<, >, <=, >=, is, as関係・型チェック
==, !=等価
&AND
^XOR
``
&&条件付きAND
`
??null合体
?:条件
=, +=, -=, ??=, =>代入・ラムダ

すべてを丸暗記する必要はありません。迷ったら丸かっこを使うのが実務では安全です。

11-4. 同じ式で複数の演算子を使う場合の評価順

次の式を見てみましょう。

C#
int result = 10 + 20 / 5 * 2;

/*+より優先順位が高く、同じ優先順位なら左から評価されます。

C#
10 + ((20 / 5) * 2)

結果は18です。

論理演算でも優先順位があります。

C#
bool result = true || false && false;

&&||より優先順位が高いため、次のように評価されます。

C#
true || (false && false)

結果はtrueです。

11-5. 丸かっこ()で評価順を明確にする方法

丸かっこを使うと、評価順を明示できます。

C#
int result1 = 2 + 3 * 4;     // 14
int result2 = (2 + 3) * 4; // 20

条件式でも同じです。

C#
if ((age >= 20 && hasTicket) || isStaff)
{
Console.WriteLine("入場できます");
}

読み手が迷いそうな式では、優先順位に頼りすぎず、丸かっこを使いましょう。

11-6. 優先順位でよくある勘違い

よくある勘違いは、&&||を混ぜた条件式です。

C#
if (isAdmin || isMember && hasPaid)
{
Console.WriteLine("アクセス許可");
}

これは次の意味です。

C#
if (isAdmin || (isMember && hasPaid))
{
}

もし「管理者または会員」で、かつ「支払い済み」にしたいなら、次のように書きます。

C#
if ((isAdmin || isMember) && hasPaid)
{
Console.WriteLine("アクセス許可");
}

優先順位を理解していても、業務コードでは明確さを優先しましょう。

12. C# operatorsの実践的な使い方

12-1. 条件分岐でよく使う演算子の組み合わせ

条件分岐では、比較演算子と論理演算子を組み合わせます。

C#
if (score >= 60 && attendanceRate >= 0.8)
{
Console.WriteLine("合格");
}

範囲チェックでは、次のような書き方がよく使われます。

C#
if (age >= 20 && age < 65)
{
Console.WriteLine("対象年齢です");
}

否定条件には!を使います。

C#
if (!string.IsNullOrEmpty(name))
{
Console.WriteLine(name);
}

12-2. null安全なコードを書く演算子の組み合わせ

null安全なコードでは、?.??の組み合わせが非常に便利です。

C#
string displayName = user?.Profile?.DisplayName ?? "ゲスト";

このコードは、userProfileがnullでも例外にならず、最終的に"ゲスト"を返します。

メソッド呼び出しも安全にできます。

C#
logger?.Log("処理を開始しました");

コレクション初期化には??=を使います。

C#
items ??= new List<Item>();
items.Add(item);

12-3. 配列・List・文字列操作で使う演算子

配列やListでは、[]^..がよく使われます。

C#
List<string> names = new() { "Alice", "Bob", "Charlie" };

Console.WriteLine(names[0]);
Console.WriteLine(names[^1]);

配列の一部を取り出すには範囲演算子を使えます。

C#
int[] numbers = { 1, 2, 3, 4, 5 };

int[] part = numbers[1..4];

文字列の切り出しにも便利です。

C#
string code = "ABC-12345";

string prefix = code[..3];
string number = code[4..];

12-4. LINQやラムダ式で使う演算子

LINQでは、ラムダ演算子=>、比較演算子、論理演算子が頻繁に登場します。

C#
List<int> numbers = new() { 1, 2, 3, 4, 5, 6 };

var result = numbers
.Where(x => x % 2 == 0)
.Select(x => x * 10);

オブジェクトの絞り込みでも使います。

C#
var activeUsers = users
.Where(user => user.IsActive && user.Age >= 20)
.ToList();

null対策も組み合わせられます。

C#
var names = users
.Select(user => user.Name ?? "未設定")
.ToList();

12-5. 実務コードで読みやすく書くコツ

実務では、短さよりも読みやすさが重要です。次のような点を意識しましょう。

C#
// 読みにくい
var result = user != null && user.Age >= 20 && user.IsActive && !user.IsDeleted ? "OK" : "NG";

条件が長い場合は、意味のある変数に分けます。

C#
bool isAdult = user?.Age >= 20;
bool canUseService = user != null && isAdult && user.IsActive && !user.IsDeleted;

string result = canUseService ? "OK" : "NG";

また、優先順位に頼りすぎず、丸かっこを使うと意図が伝わりやすくなります。

C#
if ((isAdmin || isOwner) && !isSuspended)
{
Console.WriteLine("操作できます");
}

13. 演算子のオーバーロード

13-1. 演算子オーバーロードとは

演算子オーバーロードとは、独自の型に対して+==などの演算子の動作を定義する機能です。

たとえば、Money型を作った場合、次のように書けると自然です。

C#
Money total = price1 + price2;

C#では、ユーザー定義型に対して既存の演算子をオーバーロードし、独自の動作を実装できます。

13-2. operatorキーワードの使い方

演算子をオーバーロードするには、operatorキーワードを使います。

C#
public readonly struct Money
{
public decimal Amount { get; }

public Money(decimal amount)
{
Amount = amount;
}

public static Money operator +(Money left, Money right)
{
return new Money(left.Amount + right.Amount);
}
}

使う側は、通常の+演算子として扱えます。

C#
Money a = new Money(1000);
Money b = new Money(500);

Money total = a + b;

Console.WriteLine(total.Amount); // 1500

13-3. オーバーロードできる演算子・できない演算子

すべての演算子をオーバーロードできるわけではありません。

代表的にオーバーロードできる演算子には、次のようなものがあります。

種類演算子
算術+, -, *, /, %
比較<, >, <=, >=
等価==, !=
単項+, -, !, ~, ++, --
ビット&, `

一方、.?.??&&||==>などは直接オーバーロードできません。

13-4. 独自クラスで+や==を定義する例

Money型で+==を定義する例です。

C#
public readonly struct Money
{
public decimal Amount { get; }

public Money(decimal amount)
{
Amount = amount;
}

public static Money operator +(Money left, Money right)
{
return new Money(left.Amount + right.Amount);
}

public static bool operator ==(Money left, Money right)
{
return left.Amount == right.Amount;
}

public static bool operator !=(Money left, Money right)
{
return !(left == right);
}

public override bool Equals(object? obj)
{
return obj is Money money && Amount == money.Amount;
}

public override int GetHashCode()
{
return Amount.GetHashCode();
}
}

==をオーバーロードする場合は、通常!=EqualsGetHashCodeも整合性が取れるように実装します。

13-5. 演算子オーバーロードを使うべき場面と注意点

演算子オーバーロードは便利ですが、使いすぎるとコードの意味がわかりにくくなります。

使うべき場面は、数学的・直感的に自然な操作を表す場合です。

C#
Vector v3 = v1 + v2;
Money total = price + tax;

避けたい例は、演算子の意味が直感と合わない場合です。

C#
// +なのにデータベースへ保存する、などは不自然

演算子は短く書ける分、意味が伝わりにくいこともあります。独自型で使う場合は、誰が読んでも自然に理解できる動作に限定しましょう。

14. C# operatorsでよくあるエラーと解決策

14-1. =と==を間違える

=は代入、==は比較です。

C#
int x = 10;

// 比較
if (x == 10)
{
Console.WriteLine("10です");
}

bool変数で代入を条件に書いてしまうと、意図しない動作になります。

C#
bool isValid = false;

// 避けたい
if (isValid = true)
{
}

次のように書きましょう。

C#
if (isValid)
{
}

14-2. &&と&を混同する

条件式では基本的に&&を使います。

C#
if (user != null && user.IsActive)
{
Console.WriteLine("有効ユーザー");
}

&を使うと右側も必ず評価されるため、nullチェックでは危険です。

C#
// userがnullだと例外の可能性
if (user != null & user.IsActive)
{
}

|||も同様です。条件式では&&||を基本にしましょう。

14-3. 整数除算で期待通りの結果にならない

整数同士の割り算は整数になります。

C#
int result = 5 / 2;
Console.WriteLine(result); // 2

小数が必要なら、doubledecimalを使います。

C#
double result = 5.0 / 2;
Console.WriteLine(result); // 2.5

金額計算ではdecimalがよく使われます。

C#
decimal result = 5m / 2m;
Console.WriteLine(result); // 2.5

14-4. null関連演算子を誤って使う

?.はnullならnullを返しますが、後続の処理によってはまだ注意が必要です。

C#
int? length = user?.Name?.Length;

intに直接代入するとエラーになります。

C#
// int length = user?.Name?.Length; // エラー

代替値を指定するなら??を使います。

C#
int length = user?.Name?.Length ?? 0;

また、!は実行時のnullチェックではありません。

C#
Console.WriteLine(user!.Name);

本当にnullでない保証がある場合だけ使いましょう。

14-5. 優先順位の誤解で結果が変わる

次のコードは、意図と違う可能性があります。

C#
if (isAdmin || isUser && isActive)
{
}

&&が先に評価されるため、次と同じです。

C#
if (isAdmin || (isUser && isActive))
{
}

意図が違うなら丸かっこを使います。

C#
if ((isAdmin || isUser) && isActive)
{
}

優先順位を知っていても、読み手のために丸かっこを使うのが安全です。

14-6. 型変換・キャストで例外が発生する

キャストは失敗すると例外になります。

C#
object value = 123;

// InvalidCastException
// string text = (string)value;

安全に処理するならisを使います。

C#
if (value is string text)
{
Console.WriteLine(text);
}
else
{
Console.WriteLine("文字列ではありません");
}

文字列から数値への変換では、TryParseを使いましょう。

C#
string input = "123";

if (int.TryParse(input, out int number))
{
Console.WriteLine(number);
}

15. C# operatorsのチートシート

15-1. 演算子一覧表

分類演算子
算術+, -, *, /, %
インクリメント++, --
代入=, +=, -=, *=, /=, %=, ??=
比較<, >, <=, >=
等価==, !=
論理&&, `
ビット&, `
null関連??, ??=, ?., ?[], !
型関連is, as, (T), typeof, sizeof, nameof
条件?:
ラムダ=>
メンバーアクセス., [], (), ^, ..
その他new, await, default, delegate, checked, unchecked

15-2. 用途別に覚える主要演算子

計算したいときは、+-*/%を使います。

C#
int total = price * quantity;

条件を判定したいときは、==!=<><=>=を使います。

C#
bool isPassed = score >= 60;

条件を組み合わせたいときは、&&||!を使います。

C#
if (isActive && !isDeleted)
{
}

nullを安全に扱いたいときは、?.????=を使います。

C#
string name = user?.Name ?? "ゲスト";

型を確認したいときは、isを使います。

C#
if (value is string text)
{
}

15-3. 優先順位早見表

初心者がまず覚えたい優先順位は、次の流れです。

C#
.  []  ()
++ --
! キャスト
* / %
+ -
< > <= >= is as
== !=
&&
||
??
?:
= += -= ??=

特に重要なのは、次の3つです。

C#
* / %  + - より先
&& || より先
代入 = はかなり後

迷ったら丸かっこを使います。

C#
int result = (a + b) * c;

15-4. 初心者が最初に覚えるべき演算子

初心者が最初に覚えるべきC# operatorsは、次のあたりです。

用途演算子
代入=
計算+, -, *, /, %
比較==, !=, <, >, <=, >=
条件&&, `
カウント++, --
null対策??, ?.
メンバーアクセス., []

まずは、if文、for文、配列、文字列操作で使う演算子を優先的に覚えましょう。

15-5. 中級者が押さえたい演算子

中級者になったら、次の演算子も押さえておくと実務コードが読みやすくなります。

用途演算子
null初期化??=
型チェックis
安全な型変換as
パターンマッチングis, switch
ラムダ式=>
範囲操作^, ..
ビット管理&, `
オーバーフロー制御checked, unchecked
演算子オーバーロードoperator

これらを理解すると、LINQ、null安全な設計、独自型の実装、パフォーマンスを意識したコードにも対応しやすくなります。

まとめ

C# operatorsは、C#プログラミングの基礎であり、計算、代入、比較、条件分岐、null処理、型変換、配列操作、LINQ、オブジェクト指向の実装まで、あらゆる場面で使われます。

初心者は、まず=+-*/%==!=&&||!.[]を確実に理解しましょう。その後、???.is=>^..などを覚えると、より実践的なC#コードが書けるようになります。

演算子で特に大切なのは、記号の意味だけでなく、評価順、優先順位、副作用、null安全性を理解することです。複雑な式では丸かっこを使い、読みやすさを優先しましょう。

C# operatorsを正しく使えるようになると、コードの意図を短く明確に表現でき、バグの少ない読みやすいプログラムを書けるようになります。