2016-08-10 4 views
2

this articleによると、Equal(Thing)を以下のように伴いました。比較演算子を設計するときのStackOverflow

public override int GetHashCode() { return Id.GetHashCode(); } 

public override bool Equals(object input) 
{ 
    Thing comparee = input as Thing; 
    return comparee != null && comparee.Id == Id; 
} 

public static bool operator ==(Thing self, Thing other) 
{ 
    return self != null && other != null && self.Id == other.Id; 
} 

public static bool operator !=(Thing self, Thing other) 
{ 
    return self == null || other == null || self.Id != other.Id; 
} 

問題は、それは私がオペレータの再定義を追加する前に働いていたが、今私はStackOverflowExceptionがを得ることです。私は何が欠けていますか?

答えて

3

が、しかしそこので、ここで、私はこの場合にはしたいと思い、別のポイントであり、私はそれを実装する方法を次のとおりです。等しい基準を使用して

public static bool operator ==(Thing self, Thing other) 
{ 
    return !ReferenceEquals(self, null) && 
      !ReferenceEquals(other, null) && 
      self.Id == other.Id; 
} 

public static bool operator !=(Thing self, Thing other) 
{ 
    return !(self == other); 
} 

は、スタックオーバーフローが発生することはありませんオペレーター==/!=オペレーターを使用せず、オペレーターの!を単に返すように!=を実装すると、同等性テストが変更される場合に備えて保守が省かれます。これはDRY原則の実装です。

+0

私は、ある場所でしか変化の滑らかさを見ません。しかし、あなたはどのように感じるでしょうか?ReturnEquals(self、other)|| self?.Id == other?.Id; *等価と*リターンのために!ReferenceEquals(self、other)||自己ですか?Id!=他?.Id; *不等式のために? –

+0

私はそうだと思います。等価演算子を実装することを選択したにもかかわらず、等価演算子ではなく単に等しくない演算子を実装する方が良いです。それは私の答えの全体のポイントです - あなたが一度だけ実装できるものを2回実装しないでください。 –

+0

@ KonradViltersten:あなたのロジックがちょっと混乱しているように見えます。 '!a || bは '!(a || b)'と同じではありません。 (理由#7なぜ1つの場所にロジックを持ち、それ以外のものはそれを参照している方が良いのでしょうか。:) – cHao

5

Thingを比較する==演算子を定義すると、someThing == nullと言うときに使用されます。同様に!=と同じです。

self == otherと言うと、operator ==(self, other)と呼ばれることになります。あなたの基準の中でoperator !=(self, null)を呼び出すself != nullがあります。self == nullをチェックし、operator ==(self, null)を呼び出すと、スタックスペースが足りなくなるまで行くことになります。

リファレンス比較のために、資料をobjectにキャストすることでこの問題を回避できることは間違いありません。または、Object.ReferenceEquals(self, null)などと言うことができます。これは==に依存しないため、再帰を取得しません。

私は完全にチャオの答えに同意