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

Posted

技术标签:

【中文标题】结构中需要覆盖啥以确保平等正常运行?【英文标题】:What needs to be overridden in a struct to ensure equality operates properly?结构中需要覆盖什么以确保平等正常运行? 【发布时间】:2010-12-02 21:55:08 【问题描述】:

正如标题所说:我需要覆盖== 运算符吗? .Equals() 方法怎么样?我有什么遗漏吗?

【问题讨论】:

还要注意***.com/questions/1972262/…——如果你不小心,那么你的结构(一个值类型)与 null 的比较会编译得很好,但不会像你期望的那样。 【参考方案1】:

来自 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);
   

【讨论】:

我想知道使用Complex other = obj as Complex然后检查other == null而不是使用is然后进行演员表会不会更好... @Clement:你不能为一个结构做那个;结果不能为空。你会得到一个编译错误。 @MatthewWatson:我认为可以使用Complex? other = obj as Complex?,但可空类型通常不适合效率。 @HaraldCoppoolse - 自然密封的值类型,因此无法按照您的建议派生 MyComplex 为什么 obj 不是 SaveOptions op && this == op; ?【参考方案2】:

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

看看那个帖子: Which is best for data store Struct/Classes?

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

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

问候,最好的代码

【讨论】:

反射比手动实现要慢很多。如果您关心性能,请手动编写它们。【参考方案3】:

为了完整起见,我还建议重载 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/

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

哈希码冲突不一定是个问题。事实上,您总是有可能发生碰撞(阅读鸽子洞/生日悖论)在您的情况下,Complex(1,4) 和 Complex(4,1) 发生碰撞(诚然碰撞较少),这取决于您的数据.哈希码用于快速清除 99.999% 的不需要的对象(例如,在字典中)相等运算符拥有最终决定权。 据说结构上的属性越多,发生冲突的可能性就越大。这可能是一个更好的哈希算法:***.com/a/263416/309634【参考方案5】:

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

【讨论】:

【参考方案6】:

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

务必在值类型上实现 IEquatable。 值类型上的 Object.Equals 方法会导致装箱,它的 默认实现不是很有效,因为它使用反射。 IEquatable.Equals 可以提供更好的性能并且可以 实施后不会引起装箱。

public struct Int32 : IEquatable<Int32> 
    public bool Equals(Int32 other) ... 

请遵循与 覆盖 Object.Equals 时 实现 IEquatable.Equals。 详见 8.7.1 节 覆盖 Object.Equals 的指南

【讨论】:

所以这仅用于值类型? (不是参考?) 因为引用类型在作为对象传递时不需要装箱,因此 IEquatable 不会提供任何好处。值类型通常被完全复制到堆栈中(或外部类型布局),因此要获得对它的对象引用并正确处理对象的生命周期,需要将其装箱(用特殊类型包装)并复制到堆;只有这样才能将堆对象的引用传递给 Object.Equals 之类的函数。

以上是关于结构中需要覆盖啥以确保平等正常运行?的主要内容,如果未能解决你的问题,请参考以下文章

我可以更改啥以使此代码正常工作?

我需要更改啥以允许我的 IIS7 ASP.Net 3.5 应用程序创建事件源并将事件记录到 Windows EventLog?

在命令行中输入啥以在散景服务应用程序中运行 spark?我是不是只需用 && 分隔两个命令行条目?

轻松地在Java的Collections接口中更改.contains()方法,以确保平等

不等键的自定义连接

springcloud Eureka自我保护机制