结构中需要覆盖啥以确保平等正常运行?
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以上是关于结构中需要覆盖啥以确保平等正常运行?的主要内容,如果未能解决你的问题,请参考以下文章
我需要更改啥以允许我的 IIS7 ASP.Net 3.5 应用程序创建事件源并将事件记录到 Windows EventLog?
在命令行中输入啥以在散景服务应用程序中运行 spark?我是不是只需用 && 分隔两个命令行条目?