web-dev-qa-db-ja.com

平等が適切に機能することを保証するために、構造体で何をオーバーライドする必要がありますか?

タイトルにあるように:_==_演算子をオーバーライドする必要がありますか? .Equals()メソッドはどうですか?私が不足しているものは何ですか?

70
RCIX

Msdnの例

public struct Complex 
{
   double re, im;
   public override bool Equals(Object obj) 
   {
      return obj is Complex && this == (Complex)obj;
   }
   public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }
   public static bool operator ==(Complex x, Complex y) 
   {
      return x.re == y.re && x.im == y.im;
   }
   public static bool operator !=(Complex x, Complex y) 
   {
      return !(x == y);
   }
}
83
UpTheCreek

IEquatable <T>も実装する必要があります。以下は、フレームワーク設計ガイドラインからの抜粋です。

値型にIEquatableを実装してください。値型のObject.Equalsメソッドはボックス化の原因になり、デフォルトの実装は反射を使用するためあまり効率的ではありません。 IEquatable.Equalsは、はるかに優れたパフォーマンスを提供し、ボクシングを引き起こさないように実装できます。

public struct Int32 : IEquatable<Int32> {
    public bool Equals(Int32 other){ ... }
}

IEquatable.Equalsを実装するときにObject.Equalsをオーバーライドする場合と同じガイドラインに従ってください。 Object.Equalsのオーバーライドに関する詳細なガイドラインについては、セクション8.7.1を参照してください

44
Dzmitry Huba

残念ながら、他のエントリにコメントするほどの評判はありません。そこで、ここでトップのソリューションに可能な拡張機能を投稿しています。

私が間違っている場合は修正してくださいが、上記の実装

public struct Complex 
{
   double re, im;
   public override bool Equals(Object obj) 
   {
      return obj is Complex && this == (Complex)obj;
   }
   public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }
   public static bool operator ==(Complex x, Complex y) 
   {
      return x.re == y.re && x.im == y.im;
   }
   public static bool operator !=(Complex x, Complex y) 
   {
      return !(x == y);
   }
}

重大な欠陥があります。私が言及しています

  public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }

XORは対称であるため、Complex(2,1)とComplex(1,2)は同じhashCodeを返します。

おそらく次のようなものを作成する必要があります。

  public override int GetHashCode() 
   {
      return re.GetHashCode() * 17 ^ im.GetHashCode();
   }
14
Ajk

ほとんどの場合、EqualsとGetHashcodeを構造体に実装することを避けることができます。これは、参照メンバーにビット単位のコンテンツ+リフレクションを使用するValue型のコンパイラによる自動実装があるためです。

その投稿を見てください: データストアStruct/Classesに最適ですか?

したがって、使いやすさのために==と!=を実装することもできます。

ただし、ほとんどの場合、EqualsおよびGetHashcodeの実装を回避できます。
EqualsとGetHashCodeを実装する必要がある場合は、考慮したくないフィールドです。
たとえば、Age of a PersonやinstantSpeed of carのように時間とともに変化するフィールド(オブジェクトを同じ場所の辞書で検索する場合、オブジェクトのIDは変更しないでください)

よろしく、最高のコード

9
Emmanuel DURIN

2つの基本的な違いは、==演算子は静的です。つまり、呼び出す適切なメソッドはコンパイル時に決定されますが、Equalsメソッドはインスタンスで動的に呼び出されます。

3
Paolo Tedesco

完了のために、Equalsメソッドをオーバーロードすることもお勧めします。

_public bool Equals(Complex other) 
{
   return other.re == re && other.im == im;
}
_

Equals(Object obj)メソッドの入力引数のボックス化が発生しないため、これは大幅な改善です。

値型を使用するための最良の実践:

  • それらを不変にする
  • 上書き(オブジェクトを引数として取る);
  • オーバーロードEqualsは、同じ値型の別のインスタンスを取得します(例:* Equals(Complex other));
  • 過負荷演算子==および!=;
  • getHashCodeをオーバーライドします

これはこの投稿から来ています: http://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/

0
Tomasz Jaskuλa