2009-09-14 18 views
7

IComparableをオーバーライドもGetHashCodeメソッドをオーバーライドする必要があります等しいというEquals.Typesをオーバーライドする必要があります実装MSDNIComparableをとequals()

タイプから。そうしないと、Hashtableが正しく動作しない可能性があります。

私はそれを得ていませんでした。誰でも説明できますか?

+0

さらにEqualsとGetHashCodeの関係については、http:// stackoverflowを参照してください。com/questions/371328/over-this-with-equals-method-over-in-c –

+0

IComparable、Equals、およびContractの契約は必要ですが、 GetHashCode()はすべての場合に守られていますが、一貫した結果が得られる限り、必ずしも3つすべてを明示的に実装する必要はありません。主に同じハッシュコードを持つ2つのオブジェクトが等しいことを意味し、CompareTo()で0を返します。 – rushinge

+0

@rushinge文が間違っていると思います。「主に、同じハッシュコードを持つ2つのオブジェクトが等しいことを意味し、CompareTo()で0を返します。 。オブジェクトが等しい場合は、GetHashCode()で同じ値を返し、CompareTo()で0を返すことをお勧めします。同じハッシュコードを返す異なる/同じでないインスタンスを簡単に作成できます:) –

答えて

11

IComparableは、実装クラスの2つのインスタンスが互いにより大きい、より小さい、または等しいとみなせることを定義するインターフェイスです。そのインタフェースのメソッドで等値を定義しているので、2つの結果が一致するようにEqualsメソッド(および等価演算子)をオーバーライドする必要があります。

public class EqualityTest : IComparable<EqualityTest> 
{ 
     public int Value { get; set; } 

     public int CompareTo(EqualityTest other) 
     { 
      return this.Value.CompareTo(other.Value); 
     } 
} 

上記の例では、IComparableを実装しましたが、オーバーライドされたEqualsは実装されていません。同じValueを持つクラスの2つの別々のインスタンスでCompareToを呼び出すと、等しいと言います。同じ2つのインスタンスでEqualsを呼び出すと、ではなくでないと判断され、同じオブジェクトであるかどうかがテストされます(デフォルトのEqualsの実装)。

二つの等しい項目が(急速ハッシュテーブルのキーとして使用されるアイテムを見つけるために使用される)同じハッシュコードを返す必要がありますので、その後に等しいオーバーライドする場合はまた、GetHashCodeメソッド()


をオーバーライドする必要がありますたとえば私はちょうど私のIDEに以下のクラスを作成しました:

public class EqualityTest 
{ 
    public string A { get; set; } 
    public string B { get; set; } 
} 

そして、私は平等に影響を与えるためにAとBの両方を望んでいたと言ってReSharperのの役に立つ「平等を生成」機能を実行しました。だから、あなたが上書きされている場合は、あなたはまた、あなたがIComparableをを実装しているならば、同じことが適用され、一貫性を確保するために、上記のすべてを定義する必要があり等しい

public bool Equals(EqualityTest other) 
    { 
     if (ReferenceEquals(null, other)) 
     { 
      return false; 
     } 

     if (ReferenceEquals(this, other)) 
     { 
      return true; 
     } 

     return Equals(other.A, A) && Equals(other.B, B); 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) 
     { 
      return false; 
     } 

     if (ReferenceEquals(this, obj)) 
     { 
      return true; 
     } 

     if (obj.GetType() != typeof(EqualityTest)) 
     { 
      return false; 
     } 

     return Equals((EqualityTest)obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      return ((A != null ? A.GetHashCode() : 0)*397)^(B != null ? B.GetHashCode() : 0); 
     } 
    } 

    public static bool operator ==(EqualityTest left, EqualityTest right) 
    { 
     return Equals(left, right); 
    } 

    public static bool operator !=(EqualityTest left, EqualityTest right) 
    { 
     return !Equals(left, right); 
    } 

:これは、作成したコードです。

+0

私の考えでは、型は一般的に明確な順位を持つ可能性があるが、互いに等価ではないが、互いに自然な順位を持たない値のグループが存在する可能性があるため、 'CompareTo()'が返すのに完全に適切である'Equals()'がfalseを返すようにします(例えば、 'Decimal'は' 1.0m'と '1.00m'を比較するときにそのように振る舞うはずです)。私の考えでは、 'Equals'は、' == 'や' CompareTo'がより緩やかなものを定義する場合であっても、比較的厳密な等式関係を定義しなければなりません。 – supercat

0

あなたのコード内のオブジェクトを比較できる2つの方法があります。すべての状況で適切に比較するためにあなたのオブジェクトの場合EqualsGetHashCode

、あなたは(いくつかの比較に使用)Equalsメソッドをオーバーライドするとき、あなたがしなければならないが、 GetHashCode(他の部分で使用されています)をオーバーライドします。

コードに応じて1つをオーバーライドしますが、他のコードをオーバーライドしないと、予期しない結果が発生する可能性があります。

1

IComparableは、2つのオブジェクトの比較に使用されます。これらが等しいと見なされると、Compareは0を返します。IComparable.Compareが2つのオブジェクトに対してゼロを返したにもかかわらず、obj1.Equals(obj2)オブジェクトの平等の2つの異なる意味を暗示する。

クラスが等しいをオーバーライドする場合、2つの等しいオブジェクトが同じ値にハッシュする必要があり、このハッシュは等価の実装で使用されるフィールド/プロパティに基づいている必要があるため、GetHashCodeもオーバーライドする必要があります。

+0

IComparable.Compareがゼロを返す場合、これは実際にアイテムが等しいと見なされることを意味するのか、単に明確な順序関係が存在しないことを意味しますか?たとえば、DateTime型のEventTimeフィールドとMethodInvoker型のEventActionフィールドを含む不変クラスのScheduleEventがあるとします。 ScheduleEventオブジェクトは、EventTimeに基づく自然順序付けを持っていますが、同じEventTimeを持つScheduleEventオブジェクトを平均しますが、異なる代理人はCompareToから0を返しますが、EqualsからFalseを返す必要があります。それは他のどのような行動よりもきれいに見えます。 – supercat