74

正如标题所说:我需要覆盖==操作员吗?方法怎么样.Equals()?有什么我想念的吗?

4

6 回答 6

90

来自 msdn 的示例

public struct Complex 
{
   double re, im;
   public override bool Equals(Object obj) 
   {
        return obj is Complex c && this == c;
   }
   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);
   }
}
于 2009-10-01T07:50:18.753 回答
46

您还应该实现 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 节

于 2009-10-01T07:52:44.363 回答
15

不幸的是,我没有足够的声誉来评论其他条目。所以我在这里发布了对顶级解决方案的可能增强。

纠正我,如果我错了,但上面提到的实现

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();
   }

XORing 是对称的,所以 Complex(2,1) 和 Complex(1,2) 会给出相同的 hashCode。

我们可能应该做一些更像:

  public override int GetHashCode() 
   {
      return re.GetHashCode() * 17 ^ im.GetHashCode();
   }
于 2013-11-21T16:35:34.497 回答
10

大多数情况下,您可以避免在结构中实现 Equals 和 GetHashcode - 因为编译器使用按位内容 + 反射作为引用成员的值类型自动实现。

看看那个帖子: 哪个最适合数据存储结构/类?

因此,为了便于使用,您仍然可以实现 == 和 !=。

但大多数时候你可以避免实现 Equals 和 GetHashcode。
您必须实现 Equals 和 GetHashCode 的情况是针对您不想考虑的字段。
例如,随着时间的推移而变化的字段,例如人的年龄或汽车的即时速度(如果您想在字典中的同一位置找到它,则对象的身份不应该改变)

问候,最好的代码

于 2015-09-26T13:19:26.243 回答
3

两者的基本区别在于==操作符是静态的,即调用的适当方法是在编译时确定的,而Equals方法是在实例上动态调用的。
定义两者可能是最好的做法,即使这在结构的情况下不那么重要,因为结构不能扩展(一个结构不能从另一个继承)。

于 2009-10-01T07:50:38.300 回答
2

为了完整起见,我还建议重载Equals方法:

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

Equals(Object obj)这是一个真正的快速改进,因为方法的输入参数没有发生装箱

使用值类型的一些最佳实践:

  • 使它们不可变
  • 覆盖 Equals(将对象作为参数的那个);
  • 重载 Equals 以获取相同值类型的另一个实例(例如 * Equals(Complex other));
  • 重载运算符 == 和 !=;
  • 覆盖 GetHashCode

这来自这篇文章:http ://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/

于 2015-07-24T15:00:10.760 回答