需要在结构中覆盖什么以确保平等正常运行?

RCI*_*CIX 71 .net c# struct operators equals-operator

正如标题所说:我是否需要覆盖==运营商?怎么样的.Equals()方法?我缺少什么?

UpT*_*eek 85

msdn的一个例子

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 对于好奇:http://msdn.microsoft.com/en-us/library/336aedhh(v = VS.71).aspx (9认同)
  • @Clement:你不能为结构做到这一点; 结果不能为空.你会收到编译错误. (3认同)

Dzm*_*uba 44

您还应该实现IEquatable <T>.以下是框架设计指南的摘录:

在值类型上实现IEquatable.值类型的Object.Equals方法导致装箱,其默认实现效率不高,因为它使用了反射.IEquatable.Equals可以提供更好的性能,并且可以实现,以便它不会导致装箱.

public struct Int32 : IEquatable<Int32> {
    public bool Equals(Int32 other){ ... }
}
Run Code Online (Sandbox Code Playgroud)

在实现IEquatable.Equals时,请遵循与覆盖Object.Equals相同的指导原则.有关重写Object.Equals的详细指南,请参见第8.7.1节

  • 由于引用类型在作为对象传递时不需要装箱,因此 IEquatable&lt;T&gt; 不会提供任何好处。值类型通常会完全复制到堆栈上(或复制到外部类型布局中),因此要获取对其的对象引用,并正确处理对象的生命周期,需要将其装箱(用特殊类型包装)并复制到堆;只有这样,堆对象的引用才能传递给像 Object.Equals 这样的函数。 (2认同)

Ajk*_*Ajk 14

不幸的是,我没有足够的声誉评论其他参赛作品.所以我在这里发布了对顶级解决方案的可能增强.

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

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

有重大缺陷.我指的是

  public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }
Run Code Online (Sandbox Code Playgroud)

XORing是对称的,因此Complex(2,1)和Complex(1,2)会给出相同的hashCode.

我们应该做更像的事情:

  public override int GetHashCode() 
   {
      return re.GetHashCode() * 17 ^ im.GetHashCode();
   }
Run Code Online (Sandbox Code Playgroud)

  • 有哈希码冲突不一定是个问题.事实上,你总是有碰撞的机会(读上皮孔/生日悖论)在你的情况下,复杂(1,4)和复杂(4,1)碰撞(不可否认碰撞较少),这取决于你的数据.哈希码用于快速清除99.999%的不需要的对象(例如,在字典中).相等运算符具有最终发言权. (6认同)

Emm*_*RIN 9

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

看看那篇文章: 哪个最适合数据存储结构/类?

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

但大多数情况下,您可以避免实现Equals和GetHashcode.
您必须实现Equals和GetHashCode的情况适用于您不想考虑的字段.
例如,一个随时间变化的字段,如人的年龄或汽车的instantSpeed(如果你想在同一个地方的字典中找到它,对象的身份不应该改变)

问候,最好的代码