演算子のオーバーロード (C# リファレンス)

ユーザー定義型は定義済みの C# 演算子をオーバーロードできます。 つまり、1 つまたは両方のオペランドに該当する型では、演算のカスタム実装を提供できます。 オーバーロード可能な C# 演算子は、「オーバーロード可能な演算子」のセクションで示します。

演算子の宣言には operator キーワードを使用します。 演算子の宣言では、次の規則を満たす必要があります。

  • これには、publicstatic 修飾子の両方が含まれています。
  • 単項演算子には、1 つの入力パラメーターがあります。 2 項演算子には、2 つの入力パラメーターがあります。 どちらの場合も、少なくとも 1 つのパラメーターの型が T または T? でなければなりません。T は演算子の宣言が含まれる型です。

次の例は、有理数を表す簡略化された構造を定義しています。 構造体がいくつかの算術演算子をオーバーロードします。

using System;

public readonly struct Fraction
{
    private readonly int num;
    private readonly int den;

    public Fraction(int numerator, int denominator)
    {
        if (denominator == 0)
        {
            throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
        }
        num = numerator;
        den = denominator;
    }

    public static Fraction operator +(Fraction a) => a;
    public static Fraction operator -(Fraction a) => new Fraction(-a.num, a.den);

    public static Fraction operator +(Fraction a, Fraction b)
        => new Fraction(a.num * b.den + b.num * a.den, a.den * b.den);

    public static Fraction operator -(Fraction a, Fraction b)
        => a + (-b);

    public static Fraction operator *(Fraction a, Fraction b)
        => new Fraction(a.num * b.num, a.den * b.den);

    public static Fraction operator /(Fraction a, Fraction b)
    {
        if (b.num == 0)
        {
            throw new DivideByZeroException();
        }
        return new Fraction(a.num * b.den, a.den * b.num);
    }

    public override string ToString() => $"{num} / {den}";
}

public static class OperatorOverloading
{
    public static void Main()
    {
        var a = new Fraction(5, 4);
        var b = new Fraction(1, 2);
        Console.WriteLine(-a);   // output: -5 / 4
        Console.WriteLine(a + b);  // output: 14 / 8
        Console.WriteLine(a - b);  // output: 6 / 8
        Console.WriteLine(a * b);  // output: 5 / 8
        Console.WriteLine(a / b);  // output: 10 / 4
    }
}

int から Fraction への暗黙的な変換を定義することで、前の例を拡張できます。 その場合、オーバーロードされた演算子はこれら 2 つの型の引数をサポートします。 つまり、整数を分数に足し、結果として分数を取得できるようになります。

また、operator キーワードを使用してカスタムの型変換を定義することもできます。 詳細については、「ユーザー定義の変換演算子」 に関するページを参照してください。

オーバーロード可能な演算子

次の表は、C# 演算子のオーバーロード可/不可に関する情報を示します。

演算子 オーバーロード可/不可
+x-x!x~x++--truefalse これらの単項演算子はオーバーロードできます。
x + yx - yx * yx / yx % yx & yx | yx ^ yx << y, x >> yx == yx != yx < y, x > yx <= y, x >= y これらの 2 項演算子はオーバーロードできます。 特定の演算子はペアでオーバーロードする必要があります。詳細については、この表の後にある注を参照してください。
x && yx || y 条件付き論理演算子は、オーバーロードできません。 ただし、オーバーロードされた true および false 演算子を含む型が特定の方法で & または | もオーバーロードしている場合は、その型のオペランドに対してそれぞれ && または || 演算子の評価が可能になります。 詳細については、「C# 言語仕様」のユーザー定義型条件論理演算子に関するセクションを参照してください。
a[i], a?[i] 要素へのアクセスはオーバーロード可能な演算子とは見なされていませんが、インデクサーを定義することができます。
(T)x キャスト演算子をオーバーロードすることはできませんが、キャスト式で実行できるカスタム型変換を定義することはできます。 詳細については、「ユーザー定義の変換演算子」 に関するページを参照してください。
+=-=*=/=%=&=|=^=<<=, >>= 複合代入演算子を明示的にオーバーロードすることはできません。 ただし、二項演算子をオーバーロードするとき、対応する複合代入演算子がある場合は、それも暗黙的にオーバーロードされます。 たとえば、+= は、オーバーロード可能な + を使用して評価されます。
^xx = yx.yx?.yc ? t : fx ?? yx ??= yx..yx->y=>f(x)asawaitcheckeduncheckeddefaultdelegateisnameofnewsizeofstackallocswitchtypeofwith これらの演算子はオーバーロードできません。

注意

比較演算子は、ペアでオーバーロードする必要があります。 つまり、ペアのどちらかの演算子をオーバーロードする場合、もう一方の演算子もオーバーロードする必要があります。 次のようなペアがこれに該当します。

  • == 演算子と != 演算子
  • < 演算子と > 演算子
  • <= 演算子と >= 演算子

C# 言語仕様

詳細については、「C# 言語仕様」の次のセクションを参照してください。

関連項目