2009-10-31 50 views
3

我已经得到这个权利了一些问题,所以我想问问,如果任何人有这是否是实现自定义不可变类Equals方法和平等/不平等运营商的有效途径的任何反馈。这些操作员被我的程序非常频繁地调用,所以我想确保让他们正确。这是实现Equals和平等/不平等运营良好/有效的成语?

class MyObj 
{ 

    public static bool operator ==(MyObj a, MyObj b) 
    { 
     if (!object.ReferenceEquals(a, null)) 
      return a.Equals(b); 
     else if (!object.ReferenceEquals(b, null)) 
      return b.Equals(a); 
     else 
      // both are null 
      return true; 
    } 

    public static bool operator !=(MyObj a, MyObj b) 
    { 
     if (!object.ReferenceEquals(a, null)) 
      return !a.Equals(b); 
     else if (!object.ReferenceEquals(b, null)) 
      return !b.Equals(a); 
     else 
      // both are null 
      return false 
    } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as MyObj); 
    } 

    public bool Equals(MyObj obj) 
    { 
     if (object.ReferenceEquals(obj, null)) 
      return false; 
     else 
      return (obj.FieldOne == this.FieldOne && 
        obj.FieldTwo == this.FieldTwo && ...); 
    } 

} 

回答

2

我用下面的代码片段的引用类型,具有较少的重复和更清洁的感觉,在我看来。拥有一个静态的“Equals”方法允许没有运算符重载的.NET语言比较您的实例,而无需在调用实例方法之前测试null。如果你正在实现平等运算符,如果可以的话,最好让你的类不可变。

class Foo : IEquatable<Foo> 
{ 
    public override bool Equals(object obj) 
    { 
     return Equals(obj as Foo); 
    } 

    public bool Equals(Foo other) 
    { 
     if (object.ReferenceEquals(other, null)) return false; 

     // Optional early out 
     if (object.ReferenceEquals(this, other)) return true; 

     // Compare fields here 
    } 

    public static bool Equals(Foo a, Foo b) 
    { 
     if (ReferenceEquals(a, null)) return ReferenceEquals(b, null); 
     return a.Equals(b); 
    } 

    public static bool operator ==(Foo a, Foo b) 
    { 
     return Equals(a, b); 
    } 

    public static bool operator !=(Foo a, Foo b) 
    { 
     return !Equals(a, b); 
    } 
} 
0

基本上可以,但是有一个错误需要纠正。

Equals(object)方法调用自己而不是调用Equals(MyObj)方法,从而导致永恒循环。它应该是:

public override bool Equals(object obj) { 
    MyObj other = obj as MyObj; 
    return this.Equals(other); 
} 

或者干脆:

public override bool Equals(object obj) { 
    return this.Equals(obj as MyObj); 
} 

此外,您还可以简化不平等运营商:

public static bool operator !=(MyObj a, MyObj b) { 
    return !(a == b); 
} 
+0

这是正确的,我会修复错误。谢谢。 – 2009-10-31 16:27:55

2

有些事情我注意到:

  • 因为你覆盖了Equals,你守ld也覆盖GetHashCode
  • 由于您的Equals(MyObj)方法是整个IEquatable<MyObj>接口的有效实施,MyObj的确应该实现该接口。这也将让Dictionary<>和这样直接把你Equals(MyObj)方法的优点,而不是通过Equals(object)去。

而且我完全的Trillian的替代实现同意,我只是不愿已经直接实现a != b!(a == b)而不是!Equals(a, b)。 (微不足道的,当然差)

+0

这绝对重要,你永远不知道什么时候有人会把你的班级当作散列表键。 – 2009-10-31 17:10:21

0

如果你正在寻找的效率,我建议而不是使用此的object.ReferenceEquals(foo, null)

(object)foo == null 

这实际上等同,但避免了一个函数调用。

我也喜欢在我的所有类型中执行IEquatable<T>覆盖Equals。对于引用类型,我再往前Equals(object)Equals(Foo)

public override bool Equals(object other){return Equals(other as Foo);} 

的运算符重载可以简化为这样:

public static bool operator==(Foo a, Foo b){ 
    if((object)a == null) 
     return (object)b == null; 
    return a.Equals(b); 
} 
public static bool operator!=(Foo a, Foo b){ 
    return !(a == b); 
} 

如果需要绝对效率,但是,它可能是值得的代码,这些功能有点重复,以避免额外的功能调用,但不像(object)foo == null而不是object.ReferenceEquals(foo, null),避免函数调用需要额外的代码来维护,所以小增益可能不值得。

+0

我愿意下注object.ReferenceEquals无论如何都会被内联。 – Joren 2009-10-31 16:44:02

+0

@Joren:也许,也许不是。在我的测试中,我发现两者之间的执行时间差异很小。但是'(object)foo == null'比'object.ReferenceEquals(foo,null)'更少类型化,就像IMO一样清晰,并且不依赖内联来提高速度,所以为什么不使用它呢? – 2009-10-31 17:12:55

+0

是的,我认为(对象)foo == null是一个很好的解决方案。但我认为object.ReferenceEquals(foo,null)也很好。 – Joren 2009-10-31 17:22:10

0

我宁愿让所有的“如果这是null,则做别的......”的逻辑框架:

class MyObj : IEquatable<MyObj> { 

    public static bool operator ==(MyObj left, MyObj right) { 
    return EqualityComparer<MyObj>.Default.Equals(left, right); 
    } 

    public static bool operator !=(MyObj left, MyObj right) { 
    return !EqualityComparer<MyObj>.Default.Equals(left, right); 
    } 

    public override bool Equals(object obj) { 
    return this.Equals(obj as MyObj); 
    } 

    public bool Equals(MyObj other) { 
    return !object.ReferenceEquals(other, null) 
     && obj.FieldOne == this.FieldOne 
     && obj.FieldTwo == this.FieldTwo 
     && ... 
     ; 
    } 

    ... 

} 

What is the best algorithm for an overridden GetHashCode?见实施GetHashCode