25

以下のコードの場合

public struct Person
{
    public int ID;
    public static bool operator ==(Person a, Person b) { return  a.Equals(b); }
    public static bool operator !=(Person a, Person b) { return !a.Equals(b); }
}

コンパイラがこれらの警告を表示するのはなぜですか?
以下のメソッドを定義しないことの何が問題になっていますか?

warning CS0660: 'Person' defines operator == or operator != but
    does not override Object.Equals(object o)

warning CS0661: 'Person' defines operator == or operator != but
    does not override Object.GetHashCode()
4

8 に答える 8

22

EDIT :この回答は修正されました。とりわけ、ユーザー定義の値の型が生成されないことに注意し==、 のパフォーマンスの問題に言及する必要がありValueType.Equalsます。


一般に、すべてではなく 1 つをオーバーライドすると混乱を招きます。ユーザーは、どちらもオーバーライドされないこと、または両方が同じセマンティクスでオーバーライドされることを期待しています。

この状態に対するMicrosoft の推奨事項(とりわけ):

  • Equals メソッドを実装するときは常に、GetHashCode メソッドを実装します。これにより、Equals と GetHashCode の同期が維持されます。

  • 等価演算子 (==) を実装するたびに Equals メソッドをオーバーライドし、同じことを行うようにします。

あなたの場合、延期する正当な理由がありEquals(コンパイラは自動的に実装しません==)、これら2つだけをオーバーライドします(==/ !=)。ValueType.Equalsただし、リフレクションを使用するため、パフォーマンスの問題はまだあります。

「特定の型の Equals メソッドをオーバーライドして、メソッドのパフォーマンスを向上させ、型の等価性の概念をより厳密に表現します。」

==したがって、最後にすべて ( / !=/ )をオーバーライドすることをお勧めしますEquals。もちろん、この単純な構造体ではパフォーマンスは問題にならない場合があります。

于 2012-05-28T21:03:48.203 に答える
7

フレームワーク内には、特定の操作が常に同じ結果を生成するという一般的な期待があります。その理由は、特定の操作 (特に、アプリケーションの大部分を占める並べ替えと検索) は、意味のある一貫した結果を生成するこれらのさまざまな操作に依存しているためです。この場合、いくつかの仮定を破っています。

  • との==間に有効な演算がある場合、次のように同じ結果が生成されます。aba.Equals(b)
  • !=同様に、 との間aに有効な演算がある場合b、 と同じ結果が生成されるはずです。!a.Equals(b)
  • と の 2 つのオブジェクトab存在する場合、a == bab、ハッシュ テーブルに格納されたときに同じキーを生成する必要があります。

最初の 2 つの IMO は明らかです。2 つのオブジェクトが等しいとはどういう意味かを定義する場合は、2 つのオブジェクトが等しいことを確認できるすべての方法を含める必要があります。コンパイラは、実際にこれらの規則に従うことを強制しない (一般に、できない) ことに注意してください。オペレーターの本体の複雑なコード分析を実行して、オペレーターがすでに模倣しているかどうかを確認するつもりはありません。最悪の場合、停止問題を解決するEqualsことと同等になる可能性があるからです。

ただし、できることは、これらのルールに違反している可能性が最も高いケースをチェックすることです。特に、カスタム比較演算子を提供し、カスタムEqualsメソッドを提供していません。ここで想定しているのは、オペレーターに何か特別なことをさせたくないのであれば、わざわざオペレーターを提供する必要がないということです。その場合、同期する必要があるすべてのメソッドに対してカスタム動作を提供する必要があります。

Equalsコンパイラとは異なるものとして実装したとしても==、文句はありません。C# が愚かなことをするのを防ごうとする努力の限界に達していたでしょう。コードに微妙なバグを誤って導入することを喜んで阻止しますが、それが必要な場合は意図的にそうすることができます.

3 番目の仮定は、フレームワークの多くの内部操作がハッシュ テーブルのバリアントを使用するという事実に関係しています。私の定義では「等しい」2つのオブジェクトがある場合、これを行うことができるはずです。

if (a == b)
{
    var tbl = new HashTable();
    tbl.Add(a, "Test");

    var s = tbl[b];
    Debug.Assert(s.Equals("Test"));
}

これはハッシュ テーブルの基本的なプロパティであり、突然正しくない場合に非常に奇妙な問題を引き起こす可能性があります。

于 2012-05-28T22:10:23.330 に答える
3

私の推測では、コンパイラはメソッドで使用Equalsしていることを認識していないため、これらの警告が表示されます==

この実装があるとします

public struct  Person
{
    public int ID;
    public static bool operator ==(Person a, Person b) { return Math.Abs(a.ID - b.ID) <= 5; }
    public static bool operator !=(Person a, Person b) { return Math.Abs(a.ID - b.ID) > 5; }
}

それで

 Person p1 = new Person() { ID = 1 };
 Person p2 = new Person() { ID = 4 };

 bool b1 = p1 == p2;
 bool b2 = p1.Equals(p2);

b1は真になりますが、b2は偽になります

- 編集 -

今、あなたがこれをしたいとします

Dictionary<Person, Person> dict = new Dictionary<Person, Person>();
dict.Add(p1, p1);
var x1 = dict[p2]; //Since p2 is supposed to be equal to p1 (according to `==`), this should return p1

しかし、これはKeyNotFoundのような例外をスローします

しかし、あなたが追加した場合

public override bool Equals(object obj)
{
    return Math.Abs(ID - ((Person)obj).ID) <= 5; 
}
public override int GetHashCode()
{
    return 0;
}

あなたはあなたが望むものを手に入れるでしょう。

コンパイラは、同様の状況に直面する可能性があることを警告するだけです

于 2012-05-28T21:44:04.737 に答える
1

あなたがする必要があるのはあなたの構造体にForenameと言う別のメンバーを追加することです。

では、IDが63でフォレナームが異なる2人の人がいる場合、それらは等しいかどうか?

すべては、実装する「同じ」の定義によって異なります。

より良い例の構造体を使用し、さまざまなメソッドを実行するためのうなずきアプリケーションを記述し、同等性または同等性の定義を変更するとどうなるかを確認します。すべてがステップになっていない場合は、!(a == b)!=(a!= b)、これは本当かもしれませんが、すべてのメソッドをオーバーライドしないと、コードを使用する人は誰でもあなたの意図が何であったか疑問に思うでしょう。

基本的に、コンパイラーはあなたに善良な市民であり、あなたの意図を明確にするように言っています。

于 2012-05-28T21:49:46.570 に答える
0

おそらく、デフォルトのEquals()メソッドが実際のシステムで十分に機能するとは期待されていないためです (たとえば、クラスではIDフィールドを比較する必要があります)。

于 2012-05-28T21:03:15.087 に答える
0

オーバーライドするEqualsGetHashCode、演算子をオーバーライドする必要さえなくなります。これはよりクリーンなアプローチです。編集済み:これは構造体であるため、機能するはずです。

于 2012-05-28T21:07:05.863 に答える
0

MSDN ページを読んでください。

CS0660

CS0661

コンパイラは基本的に、「オブジェクトを比較する方法を知っていると言っているので、常にそのように比較する必要があります」と言っています。

于 2012-05-28T21:07:47.650 に答える