C#演算子(operator)完全ガイド|種類・優先順位・オーバーロードを初心者にもわかりやすく解説

はじめに

C#でプログラムを書くとき、ほぼ必ず使うのが演算子(operator)です。足し算をする+、値を代入する=、条件を比較する==、nullチェックに使う???.など、C#演算子は日常的なコードのあらゆる場面に登場します。

「csharp operator」と検索する人の多くは、C#の演算子の種類、使い方、優先順位、operatorキーワードによるオーバーロードをまとめて理解したいはずです。この記事では、初心者にもわかりやすいように、基本から実践例まで順番に解説します。

1. C#演算子(operator)とは?初心者向けに基本をわかりやすく解説

1-1. 演算子(operator)の役割とは

C#の演算子とは、値に対して計算、比較、代入、論理判定、型チェックなどの処理を行うための記号やキーワードです。

たとえば、次のコードでは+が加算演算子、=が代入演算子です。

C#
int result = 10 + 5;

このコードは「10と5を足した結果をresultに代入する」という意味になります。C#には数値計算のための演算子だけでなく、nullを扱う演算子、型を調べる演算子、ラムダ式で使う演算子など、多くの種類があります。Microsoft公式リファレンスでも、C#には多くの演算子があり、組み込み型では基本的な演算を実行できると説明されています。Microsoft Learn

1-2. オペランド・式・戻り値の基本

演算子を理解するうえで重要なのが、オペランド、式、戻り値です。

オペランドとは、演算子の対象になる値のことです。

C#
int x = 10 + 5;

この場合、105がオペランド、+が演算子、10 + 5全体が式です。そして式の結果として15が返され、変数xに代入されます。

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

C#
int a = -10;              // 単項演算子
int b = 10 + 5; // 二項演算子
string result = b > 10 ? "大きい" : "小さい"; // 条件演算子

1-3. C#の演算子を理解すると何ができるようになるか

C#演算子を理解すると、コードの読み書きが大きく楽になります。たとえば、条件分岐、ループ、nullチェック、LINQ、クラス設計などで、より簡潔で意図が伝わりやすいコードを書けるようになります。

C#
if (user != null && user.IsActive)
{
Console.WriteLine(user.Name);
}

このコードでは、!=でnullではないことを確認し、&&で「ユーザーが存在し、かつ有効である」という条件を表しています。演算子を正しく理解していれば、このような条件式を自然に読めるようになります。

1-4. 「csharp operator」で検索する人が知りたいポイント

「csharp operator」で検索する人が知りたい内容は、大きく分けると次の4つです。

知りたいこと内容
演算子の種類+==&&??isなど
使い方どのようなコードで使うか
優先順位複数の演算子があるとき、どれが先に評価されるか
オーバーロード自作クラスで+==を使えるようにする方法

この記事では、これらを順番に解説します。

2. C#演算子の種類一覧

2-1. 算術演算子

算術演算子は、数値計算に使う演算子です。

演算子意味
+加算a + b
-減算a - b
*乗算a * b
/除算a / b
%剰余a % b

Microsoft公式ドキュメントでは、算術演算子として++--、単項+、単項-*/%+-が説明されています。Microsoft Learn

2-2. 代入演算子

代入演算子は、変数に値を入れるための演算子です。

C#
int x = 10;

代表的な代入演算子は次のとおりです。

演算子意味
=代入
+=加算して代入
-=減算して代入
*=乗算して代入
/=除算して代入
%=剰余を代入
??=左辺がnullの場合のみ代入

2-3. 比較演算子

比較演算子は、2つの値を比較してtrueまたはfalseを返します。

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

bool isAdult = age >= 18;

2-4. 論理演算子

論理演算子は、複数の条件を組み合わせるときに使います。

演算子意味
&&かつ
`
!否定
C#
if (age >= 18 && hasTicket)
{
Console.WriteLine("入場できます");
}

2-5. ビット演算子

ビット演算子は、整数値をビット単位で操作するときに使います。

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

ビット演算子は、フラグ管理、低レベル処理、パフォーマンスを意識した処理などで使われます。

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

インクリメント演算子++は値を1増やし、デクリメント演算子--は値を1減らします。

C#
int count = 0;

count++;
count--;

前置と後置で動作のタイミングが異なります。

C#
int x = 5;

Console.WriteLine(++x); // 6
Console.WriteLine(x++); // 6
Console.WriteLine(x); // 7

2-7. 条件演算子

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

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

if文を短く書きたいときに便利ですが、複雑になりすぎると読みにくくなるため注意が必要です。

2-8. null関連演算子

C#にはnullを安全に扱うための演算子があります。

演算子意味
?.null条件演算子
?[]null条件インデクサ
??null合体演算子
??=null合体代入演算子
!null許容警告の抑制

????=は、左辺がnullでない場合は左辺を使い、nullの場合は別の値を使う、または代入するための演算子です。Microsoft Learn

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

型に関する代表的な演算子には、isastypeof、キャスト演算子があります。

C#
object value = "Hello";

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

Microsoft公式リファレンスでは、isは実行時の型が指定した型と互換性があるか確認し、asは互換性がある場合に変換し、互換性がない場合はnullを返す演算子として説明されています。Microsoft Learn

2-10. ラムダ演算子・メンバーアクセス演算子

ラムダ演算子=>は、ラムダ式で使います。

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

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

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

C#
Console.WriteLine(user.Name);

メンバーアクセス関連の演算子には、.[]^..?.?[]()などがあります。Microsoft Learn

3. 算術演算子の使い方

3-1. 加算・減算・乗算・除算・剰余の基本

算術演算子は、C#の中でも最も基本的な演算子です。

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 = 10;

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

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

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

C#
int result = 10 / 3;
Console.WriteLine(result); // 3

小数まで求めたい場合は、どちらか一方をdoubledecimalにします。

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

または明示的にキャストします。

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

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

3-3. 文字列結合に使われる+演算子

+演算子は数値の加算だけでなく、文字列の結合にも使われます。C#の+および+=は、数値型、文字列型、デリゲート型などで使えます。Microsoft Learn

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

string fullName = lastName + " " + firstName;

Console.WriteLine(fullName); // Yamada Taro

ただし、文字列を何度も連結する処理では、StringBuilderや文字列補間を使ったほうが読みやすい場合があります。

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

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

3-4. 算術演算子でよくあるエラーと注意点

算術演算子でよくある注意点は、ゼロ除算、整数除算、オーバーフローです。

C#
int x = 10;
int y = 0;

// int result = x / y; // 実行時エラー

また、intの範囲を超える計算にも注意が必要です。

C#
int max = int.MaxValue;
int result = max + 1;

Console.WriteLine(result);

オーバーフローを検出したい場合はcheckedを使います。

C#
checked
{
int max = int.MaxValue;
int result = max + 1;
}

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

4-1. =演算子の基本

=演算子は、右辺の値を左辺の変数に代入します。

C#
int x = 10;
string name = "Alice";

数学では=は「等しい」という意味ですが、C#では代入を意味します。等しいかどうかを比較する場合は==を使います。

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

複合代入演算子を使うと、計算と代入をまとめて書けます。

C#
int count = 10;

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

特に+=は、カウント処理や文字列連結でよく使われます。

C#
int total = 0;

total += 100;
total += 200;

Console.WriteLine(total); // 300

4-3. ??=演算子の使い方

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

C#
string? name = null;

name ??= "Guest";

Console.WriteLine(name); // Guest

すでに値が入っている場合は代入されません。

C#
string? name = "Alice";

name ??= "Guest";

Console.WriteLine(name); // Alice

初期値を安全に設定したい場面で便利です。

4-4. 代入演算子でコードを簡潔に書くコツ

代入演算子を使うときは、単に短くするだけでなく、意図が読みやすいかを意識しましょう。

C#
// 読みやすい
total += price;

// 読みにくくなりやすい
x = y = z = 10;

複数の代入を1行にまとめることもできますが、初心者のうちは1つずつ書いたほうが安全です。

5. 比較演算子と論理演算子

5-1. ==、!=、<、>、<=、>=の使い方

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

C#
int score = 75;

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

==は等しいかどうか、!=は等しくないかどうかを判定します。

C#
string role = "Admin";

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

5-2. &&、||、!の使い方

&&は両方の条件がtrueの場合にtrue、||はどちらか一方がtrueの場合にtrue、!はtrueとfalseを反転します。

C#
bool hasPermission = true;
bool isLoggedIn = true;

if (hasPermission && isLoggedIn)
{
Console.WriteLine("アクセスできます");
}
C#
bool isGuest = false;

if (!isGuest)
{
Console.WriteLine("ゲストではありません");
}

5-3. 短絡評価とは

短絡評価とは、結果が確定した時点で残りの条件を評価しない仕組みです。

C#
User? user = null;

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

このコードでは、user != nullがfalseなら、user.IsActiveは評価されません。そのため、NullReferenceExceptionを防げます。

||でも同じように、左側がtrueなら右側は評価されません。

C#
if (isAdmin || user.HasPermission)
{
Console.WriteLine("許可されています");
}

5-4. bool型と条件分岐での活用例

比較演算子や論理演算子の結果はbool型です。bool型はif文、while文、条件演算子などで使われます。

C#
bool canBuy = age >= 18 && hasMoney;

if (canBuy)
{
Console.WriteLine("購入できます");
}

条件式を変数に分けると、コードの意図がわかりやすくなります。

C#
bool isAdult = age >= 18;
bool hasTicket = ticketCount > 0;

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

5-5. ==とEqualsの違い

==Equalsは、どちらも等価性の比較に使われますが、型によって動作が異なる場合があります。

値型では、値が同じかどうかを比較するのが基本です。

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

Console.WriteLine(a == b); // True
Console.WriteLine(a.Equals(b)); // True

参照型では、==が参照の同一性を比較する場合があります。ただし、stringのように==が値比較として使えるように定義されている型もあります。

C#
string s1 = "Hello";
string s2 = "Hello";

Console.WriteLine(s1 == s2); // True
Console.WriteLine(s1.Equals(s2)); // True

自作クラスで値としての等しさを表したい場合は、EqualsGetHashCode、必要に応じて==!=を実装します。

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

6-1. null条件演算子?.の使い方

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

C#
User? user = null;

Console.WriteLine(user?.Name);

通常、user.Nameのように書くと、userがnullの場合にNullReferenceExceptionが発生します。しかし、user?.Nameなら、userがnullの場合は結果もnullになります。

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

??演算子は、左辺がnullでなければ左辺を返し、nullなら右辺を返します。

C#
string? name = null;

string displayName = name ?? "Guest";

Console.WriteLine(displayName); // Guest

設定値、ユーザー入力、APIレスポンスなどで、値がnullの場合にデフォルト値を使いたいときに便利です。

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

??=は、左辺がnullのときだけ代入します。

C#
List<string>? names = null;

names ??= new List<string>();

names.Add("Alice");

リストや辞書など、必要になったタイミングで初期化したい場合によく使います。

6-4. null許容型と演算子の関係

C#では、参照型に?を付けることでnullを許容する意図を表せます。

C#
string? nullableName = null;
string nonNullableName = "Alice";

null許容参照型を使うと、コンパイラがnullの可能性を警告してくれるため、?.????=などの演算子と組み合わせることで安全なコードを書きやすくなります。

C#
Console.WriteLine(nullableName?.Length ?? 0);

6-5. NullReferenceExceptionを防ぐ書き方

NullReferenceExceptionを防ぐには、nullチェックを明確に書くことが大切です。

C#
if (user != null)
{
Console.WriteLine(user.Name);
}

null条件演算子を使うと、より短く書けます。

C#
Console.WriteLine(user?.Name ?? "名前なし");

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

C#
user?.SendEmail();

ただし、nullのまま処理を続けてよいのか、エラーとして扱うべきなのかは設計によって異なります。単に?.で隠すのではなく、必要な場面では例外を投げる、入力チェックを行うなどの判断も重要です。

7. 型に関するC#演算子

7-1. is演算子の使い方

is演算子は、オブジェクトが指定した型かどうかを判定します。

C#
object value = "Hello";

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

パターンマッチングと組み合わせると、型チェックと変数宣言を同時に行えます。

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);
}

キャストに失敗したときに例外を出したくない場合に使えます。ただし、最近のC#ではisによるパターンマッチングのほうが読みやすい場面も多いです。

7-3. typeof演算子の使い方

typeof演算子は、型そのものを表すTypeオブジェクトを取得します。

C#
Type type = typeof(string);

Console.WriteLine(type.Name); // String

リフレクション、属性の取得、DIコンテナの登録などで使われます。

C#
Console.WriteLine(typeof(List<int>).FullName);

7-4. nameof演算子の使い方

nameof演算子は、変数名、型名、メソッド名、プロパティ名などを文字列として取得します。

C#
string name = nameof(Console);
Console.WriteLine(name); // Console

特に、例外メッセージやログで便利です。

C#
void SetName(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("名前が必要です", nameof(name));
}
}

文字列を直接書くより、リファクタリングに強くなります。

7-5. キャスト演算子との違い

キャスト演算子は、明示的に型を変換します。

C#
object value = "Hello";

string text = (string)value;

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

C#
object value = 123;

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

安全に変換したい場合は、isasを使うとよいでしょう。

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

8. C#演算子の優先順位と結合規則

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

演算子の優先順位とは、複数の演算子が1つの式に含まれるとき、どの演算子を先に評価するかを決めるルールです。Microsoft公式リファレンスでは、演算子の優先順位と結合規則がC#演算子の重要な要素として整理されています。Microsoft Learn

C#
int result = 1 + 2 * 3;

Console.WriteLine(result); // 7

この例では、+より*の優先順位が高いため、先に2 * 3が計算されます。

8-2. よく使う演算子の優先順位一覧

よく使う演算子を、優先順位が高い順にまとめると次のようになります。

優先順位演算子例内容
.[]()?.メンバーアクセス、呼び出し
++--!、キャスト単項演算
*/%乗算、除算、剰余
+-加算、減算
<><=>=isas比較、型チェック
==!=等価比較
&&論理AND
`
??null合体
?:条件演算
=+=??=代入

すべてを丸暗記する必要はありません。よく使うものから理解し、迷ったら丸括弧を使うのが実践的です。

8-3. 結合規則とは

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

たとえば、多くの二項演算子は左から右に結合します。

C#
int result = 10 - 3 - 2;

Console.WriteLine(result); // 5

これは次のように解釈されます。

C#
(10 - 3) - 2

一方、代入演算子は右から左に結合します。

C#
int a;
int b;

a = b = 10;

これは、先にb = 10が評価され、その結果がaに代入されます。

8-4. 優先順位で結果が変わるコード例

優先順位を理解していないと、意図しない結果になることがあります。

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

Console.WriteLine(result); // True

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

C#
true || (false && false)

もし左から順番に評価されると思っていると、結果を誤解してしまいます。

8-5. 迷ったら丸括弧を使うべき理由

演算子の優先順位に迷ったら、丸括弧を使いましょう。

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

丸括弧を使うと、評価順序が明確になり、コードを読む人にも意図が伝わりやすくなります。

C#
int price = 1000;
int tax = 100;
int discount = 200;

int total = (price + tax) - discount;

短さよりも、誤解されないコードのほうが重要です。

9. C#演算子のオーバーロード

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

演算子オーバーロードとは、自作クラスや構造体に対して、+-==などの演算子の動作を定義する機能です。

たとえば、座標を表すPoint型に対して、+で座標同士を足せるようにできます。

C#
Point p1 = new Point(1, 2);
Point p2 = new Point(3, 4);

Point p3 = p1 + p2;

Microsoft公式リファレンスでは、ユーザー定義型で定義済み演算子をオーバーロードし、片方または両方のオペランドがその型である場合の独自実装を提供できると説明されています。Microsoft Learn

9-2. operatorキーワードの基本構文

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

C#
public static 戻り値の型 operator 演算子(引数)
{
// 処理
}

たとえば、+演算子をオーバーロードする基本形は次のようになります。

C#
public static Point operator +(Point a, Point b)
{
return new Point(a.X + b.X, a.Y + b.Y);
}

演算子オーバーロードはpublic staticで定義します。

9-3. +演算子をオーバーロードする例

次の例では、2次元座標を表すPoint構造体に+演算子を定義しています。

C#
public readonly struct Point
{
public int X { get; }
public int Y { get; }

public Point(int x, int y)
{
X = x;
Y = y;
}

public static Point operator +(Point a, Point b)
{
return new Point(a.X + b.X, a.Y + b.Y);
}

public override string ToString()
{
return $"({X}, {Y})";
}
}

使い方は次のとおりです。

C#
Point p1 = new Point(1, 2);
Point p2 = new Point(3, 4);

Point result = p1 + p2;

Console.WriteLine(result); // (4, 6)

このように、演算子オーバーロードを使うと、独自型でも自然な書き方ができます。

9-4. ==と!=をオーバーロードする際の注意点

==をオーバーロードする場合は、通常!=もあわせて定義します。

C#
public static bool operator ==(Point a, Point b)
{
return a.X == b.X && a.Y == b.Y;
}

public static bool operator !=(Point a, Point b)
{
return !(a == b);
}

片方だけを定義すると、比較の意味が不自然になります。等価比較を定義する場合は、演算子だけでなく、EqualsGetHashCodeとの整合性も考える必要があります。

9-5. EqualsとGetHashCodeも実装すべき理由

==!=をオーバーロードするなら、EqualsGetHashCodeも実装するのが一般的です。

C#
public override bool Equals(object? obj)
{
return obj is Point other && X == other.X && Y == other.Y;
}

public override int GetHashCode()
{
return HashCode.Combine(X, Y);
}

Equalsは値として等しいかを判定するために使われ、GetHashCodeは辞書やハッシュセットなどで使われます。

C#
var set = new HashSet<Point>();

set.Add(new Point(1, 2));

Console.WriteLine(set.Contains(new Point(1, 2)));

==EqualsGetHashCodeの意味が一致していないと、コレクションで予期しない動作になることがあります。

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

C#では、すべての演算子をオーバーロードできるわけではありません。一般的に、単項演算子、算術演算子、等価演算子、比較演算子などはオーバーロード対象になります。一方で、&&||???.=.などは直接オーバーロードできません。Microsoftの設計ガイドラインでは、演算子オーバーロードは演算結果が明らかな場合に有用であり、不自然な用途では提供すべきでないとされています。Microsoft Learn

演算子オーバーロードは便利ですが、使いすぎるとコードがわかりにくくなります。たとえば、数値、座標、ベクトル、金額のように、演算の意味が直感的にわかる型で使うのがおすすめです。

10. C#演算子で初心者がつまずきやすいポイント

10-1. =と==の違い

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

C#
int x = 10;       // 代入
bool result = x == 10; // 比較

if文で間違えて=を書いてしまうミスは、初心者がよくつまずくポイントです。

C#
// if (x = 10) // C#ではintをboolとして扱えないためエラー

C#では条件式にboolが必要なため、C言語のように代入結果をそのまま条件にするミスは起きにくいですが、bool変数では注意が必要です。

C#
bool isActive = false;

if (isActive == true)
{
Console.WriteLine("有効です");
}

10-2. &&と&、||と|の違い

&&||は短絡評価を行う論理演算子です。一方、&|はビット演算子として使われますが、boolに対して使うと短絡評価を行わずに両辺を評価します。

C#
User? user = null;

if (user != null && user.IsActive)
{
Console.WriteLine("有効です");
}

この場合は安全です。しかし、&を使うと右辺も評価されます。

C#
// if (user != null & user.IsActive) // userがnullなら例外

条件式では、基本的に&&||を使いましょう。

10-3. ++iとi++の違い

++iは値を増やしてから使います。i++は値を使ってから増やします。

C#
int i = 1;

Console.WriteLine(++i); // 2
C#
int j = 1;

Console.WriteLine(j++); // 1
Console.WriteLine(j); // 2

単独で使う場合は大きな違いはありません。

C#
i++;
++i;

ただし、式の中で使うと結果が変わるため、初心者のうちは複雑な式の中で使わないほうが安全です。

10-4. null関連演算子の使い分け

null関連演算子は便利ですが、それぞれ役割が違います。

演算子使う場面
?.nullならメンバーアクセスしない
??nullならデフォルト値を使う
??=nullなら代入する
!nullではないとコンパイラに伝える
C#
string? name = null;

Console.WriteLine(name?.Length ?? 0);

!はnull許容警告を抑制できますが、実行時にnullであれば例外は発生します。

C#
string? name = GetName();

Console.WriteLine(name!.Length);

安易に!を使うより、if??で安全に処理するほうがよい場面が多いです。

10-5. 演算子の優先順位による意図しない結果

演算子の優先順位を誤解すると、想定外の結果になります。

C#
int result = 10 + 5 * 2;

Console.WriteLine(result); // 20

もし10 + 5を先に計算したいなら、丸括弧を使います。

C#
int result = (10 + 5) * 2;

Console.WriteLine(result); // 30

論理演算でも同じです。

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

10-6. 参照型の比較で起きやすいミス

参照型では、「同じ内容か」と「同じインスタンスか」を区別する必要があります。

C#
var user1 = new User { Id = 1, Name = "Alice" };
var user2 = new User { Id = 1, Name = "Alice" };

Console.WriteLine(user1 == user2); // 型の定義によって結果が変わる

自作クラスで値として比較したい場合は、Equalsを実装する、recordを使う、または比較したいプロパティを明示的に比較する方法があります。

C#
Console.WriteLine(user1.Id == user2.Id);

11. 実践でよく使うC#演算子のコード例

11-1. if文で使う比較・論理演算子

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

if (age >= 18 && hasLicense)
{
Console.WriteLine("運転できます");
}
else
{
Console.WriteLine("運転できません");
}

比較演算子と論理演算子を組み合わせることで、実践的な条件分岐を書けます。

11-2. ループ処理で使うインクリメント演算子

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

i++はループカウンタを1つ進めるためによく使われます。

C#
int count = 0;

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

11-3. nullチェックを短く書く例

通常のnullチェックは次のように書けます。

C#
if (user != null)
{
Console.WriteLine(user.Name);
}

null条件演算子とnull合体演算子を使うと、短く書けます。

C#
Console.WriteLine(user?.Name ?? "ゲスト");

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

C#
items ??= new List<string>();
items.Add("item1");

11-4. LINQやラムダ式で使う=>演算子

=>はラムダ演算子です。LINQでは非常によく使います。

C#
var numbers = new[] { 1, 2, 3, 4, 5, 6 };

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

foreach (var number in evenNumbers)
{
Console.WriteLine(number);
}

この例では、n => n % 2 == 0が「nを受け取り、nが偶数かどうかを返す関数」を表しています。

メソッドチェーンと組み合わせると、条件抽出、変換、並べ替えを簡潔に書けます。

C#
var names = users
.Where(user => user.IsActive)
.Select(user => user.Name)
.ToList();

11-5. クラス設計で使う演算子オーバーロード例

金額を表すMoney型で+演算子を使えるようにする例です。

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

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

public static Money operator +(Money a, Money b)
{
return new Money(a.Amount + b.Amount);
}

public override string ToString()
{
return $"{Amount:C}";
}
}

使い方は次のとおりです。

C#
Money price1 = new Money(1000);
Money price2 = new Money(2500);

Money total = price1 + price2;

Console.WriteLine(total);

このように、演算の意味が自然に理解できる型では、演算子オーバーロードがコードの読みやすさを高めます。

12. C#演算子に関するよくある質問

12-1. C#のoperatorとは何ですか?

C#のoperatorとは、値に対して計算、比較、代入、論理判定、型チェックなどを行うための演算子のことです。+-==&&??などの記号だけでなく、isastypeofnameofのようなキーワード形式の演算子もあります。

また、operatorキーワードは、自作型で演算子をオーバーロードするときにも使います。

C#
public static Point operator +(Point a, Point b)
{
return new Point(a.X + b.X, a.Y + b.Y);
}

12-2. C#で演算子の優先順位を覚える必要はありますか?

すべてを暗記する必要はありません。ただし、*/+-より先に評価されること、&&||より優先されること、代入演算子の優先順位が低いことは覚えておくと便利です。

迷った場合は、丸括弧を使いましょう。

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

丸括弧を使えば、コードの意図が明確になります。

12-3. C#で演算子オーバーロードはいつ使いますか?

演算子オーバーロードは、自作型に対して演算の意味が直感的にわかる場合に使います。たとえば、座標、ベクトル、複素数、金額、距離などです。

C#
Vector v3 = v1 + v2;

一方で、演算子の意味がわかりにくい場合は、通常のメソッド名を使ったほうが読みやすくなります。

C#
order.Merge(otherOrder);

演算子オーバーロードは便利ですが、使いすぎるとコードの意図が伝わりにくくなるため注意しましょう。

12-4. ==とEqualsはどちらを使うべきですか?

基本的な値型やstringでは、==を使っても自然に比較できます。

C#
string a = "Hello";
string b = "Hello";

Console.WriteLine(a == b);

自作クラスでは、何をもって等しいとするかを明確にする必要があります。値として比較したい場合は、EqualsGetHashCodeを実装し、必要に応じて==!=も定義します。

また、値オブジェクトのような用途では、recordを使う選択肢もあります。

C#
public record UserId(int Value);

12-5. 初心者が最初に覚えるべき演算子はどれですか?

初心者が最初に覚えるべきC#演算子は、次のとおりです。

分類演算子
算術+-*/%
代入=+=-=
比較==!=<><=>=
論理&&、`
null関連?.????=
型チェックisas
ラムダ=>

まずは、計算、代入、比較、論理演算を使いこなせるようになりましょう。その後、null関連演算子、型チェック、ラムダ式、演算子オーバーロードへ進むと理解しやすくなります。

まとめ

C#演算子(operator)は、C#プログラミングの基礎であり、実務コードでも頻繁に使われます。算術演算子、代入演算子、比較演算子、論理演算子、null関連演算子、型チェック演算子、ラムダ演算子などを理解することで、コードを正確に読み書きできるようになります。

特に初心者は、まず===の違い、&&||の使い方、?.??によるnull対策、演算子の優先順位を押さえることが大切です。

また、C#ではoperatorキーワードを使って演算子オーバーロードを定義できます。自作型でも+==を自然に使えるようになりますが、意味が直感的に伝わる場合に限定して使うのがよいでしょう。

「csharp operator」を理解することは、単に記号を覚えることではありません。式の意味、評価順序、型との関係、null安全性、クラス設計まで含めて理解することです。演算子を正しく使いこなせれば、C#のコードはより短く、読みやすく、安全になります。