1. ホーム
  2. c#

[解決済み] C#で演算子==はジェネリック型に適用できない?

2022-03-14 02:21:51

質問

のドキュメントによると == 演算子を MSDN ,

<ブロッククオート

定義済みの値の型については 等号演算子 (==) は、以下の場合に真を返します。 オペランドの値が等しいこと。 それ以外は偽。参照型 は、文字列以外の場合、== が真を返します。 その2つのオペランドは、同じ オブジェクトを作成します。文字列型の場合、== は文字列の値を比較する。 ユーザー定義の値型は,オーバーロードすることができる。 演算子(演算子参照)を使用します。また ユーザー定義の参照型ですが は、デフォルトで==のように動作します。 定義済みと定義済みの両方について、上記の ユーザー定義参照型

では、なぜこのコード・スニペットはコンパイルに失敗するのでしょうか?

bool Compare<T>(T x, T y) { return x == y; }

エラーが表示される 演算子 '==' は、型 'T' および 'T' のオペランドに適用できません。 . 私が理解している限りでは == 演算子はすべてのタイプであらかじめ定義されているのですか?

編集してください。 みなさん、ありがとうございます。参照型のみに関する記述であることに最初気がつきませんでした。また、ビット単位の比較はすべての値型に対して提供されていると考えていましたが、これは今となっては ではなく が正しいです。

しかし、参照型を使用している場合、このように == 演算子は定義済みの参照比較を使うのでしょうか、それとも型が定義していればオーバーロードされた演算子を使うのでしょうか?

編集2: 試行錯誤の末に == 演算子は、制限のない一般的な型を使用する場合、定義済みの参照比較を使用します。実際には、コンパイラは制限された型の引数に対して最も良い方法を使用しますが、それ以上は調べません。たとえば、次のコードは常に true の場合であっても Test.test<B>(new B(), new B()) が呼び出されます。

class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }

解決方法は?

"...デフォルトでは、定義済みおよびユーザー定義の両方の参照タイプについて、==上記のように動作します。

T型は必ずしも参照型ではないので、コンパイラはその仮定をすることができません。

しかし、これはより明示的であるため、コンパイルされます。

    bool Compare<T>(T x, T y) where T : class
    {
        return x == y;
    }

しかし、参照型を使用している場合、==演算子は定義済みの参照比較を使用するのでしょうか、それとも型が定義されている場合はオーバーロード版の演算子を使用するのでしょうか。

Genericsの==はオーバーロード版を使用すると思っていましたが、次のテストではそうでないことが証明されています。 興味深いですね。なぜなのか、ぜひ知りたいです もし知っている人がいたら教えてください。

namespace TestProject
{
 class Program
 {
    static void Main(string[] args)
    {
        Test a = new Test();
        Test b = new Test();

        Console.WriteLine("Inline:");
        bool x = a == b;
        Console.WriteLine("Generic:");
        Compare<Test>(a, b);

    }


    static bool Compare<T>(T x, T y) where T : class
    {
        return x == y;
    }
 }

 class Test
 {
    public static bool operator ==(Test a, Test b)
    {
        Console.WriteLine("Overloaded == called");
        return a.Equals(b);
    }

    public static bool operator !=(Test a, Test b)
    {
        Console.WriteLine("Overloaded != called");
        return a.Equals(b);
    }
  }
}

出力

インラインで オーバーロード == 呼ばれる

一般的なものです。

任意のキーを押して続ける . . .

フォローアップ2

ただし、比較メソッドを

    static bool Compare<T>(T x, T y) where T : Test
    {
        return x == y;
    }

は、オーバーロードされた == 演算子が呼び出されます。 型を指定しないと、( ここで というのは、コンパイラはオーバーロードされた演算子を使うべきであると推論できないからだ...たとえ型を指定しなくても、コンパイラはその判断をするのに十分な情報を持っていると思うのだが。