2009-05-27 11 views
3

次のクラスとユニットテストを受けてください。このオブジェクトの等価性テストが失敗するのはなぜですか?

public class Entity 
    { 
     public object Id { get; set; } 

     public override bool Equals(object obj) 
     { 
      return this == (Entity)obj; 
     } 

     public static bool operator == (Entity base1, Entity base2) 
     { 
      if (base1.Id != base2.Id) 
      { 
       return false; 
      } 

      return true; 
     } 

     public static bool operator != (Entity base1, Entity base2) 
     { 
      return (!(base1.Id == base2.Id)); 
     } 
    } 

 [TestMethod] 
     public void Test() 
     { 
      Entity e1 = new Entity { Id = 1 }; 
      Entity e2 = new Entity { Id = 1 }; 
      Assert.IsTrue(e1 == e2); //Always fails 
     } 

そのが失敗した理由を誰かが説明できますか?

答えて

3

あなたは、比較のためのオブジェクト参照に依存しているので:

public object Id { get; set; } 

が置き換え

public static bool operator == (Entity base1, Entity base2) 
    { 
     if (base1.Id != base2.Id) 
     { 
      return false; 
     } 

     return true; 
    } 

public static bool operator == (Entity base1, Entity base2) 
    { 
     return object.Equals(base1.Id, base2.Id); 
    } 
+0

私はnull IDに対処するためにobject.Equals(base1.Id、base2.Id)を使用します。 –

+0

良い提案。 –

+0

(もちろん、base1やbase2がnullの場合でも穴が残っていますが、他の問題もあります:) –

2

e1.Idとe2.Idは異なるオブジェクトであるためです。それらが同じ値を持っていても、それらは同じオブジェクトではないので、base1.Id == base2.Idは失敗します。

+0

Ok - 私のIDをタイプしてint型に変更するとうまくいくはずです...オブジェクト型でオーバーライド==? –

+1

*オーバーライド*演算子は決してオーバーロード*しません。通常、Equalsメソッドをオーバーライドします。 –

+0

これは、Idのコンパイル時クラスがオブジェクトであるため、デフォルトの参照参照が使用されるためです。 ==と!=あなたが期待する方法では仮想ではない==メソッドは、でコンパイルされます時間 – thecoop

1

あなたのIdプロパティはオブジェクトなので、

1(intとして)はヒープオブジェクトに囲まれますが、各1は別のインスタンスに囲まれます。 Idがオブジェクトであるため、base1.Id!= base2.Id条件は、参照の等価性を確認します。の等価性が必要です。 Idをintに変更するか、!=ではなくEquals()を使用して修正する必要があります。

2

あなたのequalsの実装は、オブジェクトの内容ではなく参照を比較するだけです。基本的に2つのポインタを比較しています.2つの別々のオブジェクトを作成しているので、等価は失敗します。

正しく対等の実装方法のいくつかの記事がありますが、ここでのスタートだ:データベース・エンティティのために

http://weblogs.asp.net/tgraham/archive/2004/03/23/94870.aspx

、あなたはショートカットを行うことができる2つのオブジェクトを想定し、単にデータベースIDを比較することによって、実装を等しいですあなたのシステムでは同じIDの「等しい」とみなされます。

2

IDはオブジェクトであり、intではありません。オブジェクトの場合、==演算子は値の等価性をチェックしません。

8

Idのプロパティはobjectです。それぞれのIDとして1を使用して2つのインスタンスを構築すると、2つの異なるボックス化オブジェクトになります。次に、これらのオブジェクトを参照等価を使用して比較しています。それが適切かどうIdのタイプはタイプintであると

  • 変更:

    は、この問題を解決するための変更を提案しました。

  • 代わり==

のIDを比較するために静的object.Equalsメソッドを使用し、これらのいずれかが動作するが、最初は、IMOが好ましいです。

興味深い場合は、実装をより明確にすることができるさまざまな方法がありますが、これはちょっとした例かもしれません。一目でだけで簡単にリスト:

  • あなたはGetHashCodeなどEqualsをオーバーライドする必要があります。
  • Equalsオーバーライドは、オブジェクトのタイプが間違っている場合に例外をスローするため、無条件にキャストを実行すべきではありません。型が間違っている場合はfalseを返します。
  • あなたの現在の==の実装はちょうど

    return base1.Id == base2.Id; 
    
  • あなたの==の実装では、それが実装することが一般的に最高だNULLかどうかをチェックし
  • を実行する必要がありますように簡略化することができます!=あなたが専門家の行動をしない限り!(base1 == base2)を返すこと。
  • 非密封クラスのEqualsを無効にすることは問題になります。あなたが継承を計画していない限り、クラスを封鎖する価値があります(IMO - これはおそらく議論の余地があります)。
+0

私が辞書のエンティティを使用しようとしていた理由は、この問題につながった理由は ...キーを取得します。だから、もし私がエンティティをDictionaryクラスで使いたいのであれば、型をintに変更しなければならないのですか? - –

+0

辞書キーとして使用しようとしている場合は、GetHashCodeをオーバーライドする必要があります。それは絶対に重要*です。いいえ、Idの型をint型に変更する必要はありませんが、==ではなく、Equalsを使用してIDを比較する必要があります。 GetHashCodeの実装では、Idのハッシュコードを使うことができます。 –

0

Idメンバーをintにした場合、正常に機能します。しかし、CookieOfFortuneが言っているように、2つのオブジェクトを比較しているとき、同じ値であるかどうかではなく、まったく同じオブジェクトであるかどうかを調べています。

0

変更int型へのIdの種類、または他の値でタイプ。問題は2つのオブジェクトを比較していることです。問題を解決するには==演算子をオーバーロードして解決してください。

関連する問題