在.NET GetHashCode方法中,很多地方都使用.NET 方法.特别是在快速查找集合中的项目或确定相等性时.是否有关于如何GetHashCode为我的自定义类实现覆盖的标准算法/最佳实践,因此我不会降低性能?
我在Silverlight应用程序中有一个比较2个字符串的条件,由于某种原因,当我使用==它时返回false而.Equals()返回true.
这是代码:
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
// Execute code
}
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
// Execute code
}
Run Code Online (Sandbox Code Playgroud)
任何理由为什么会这样?
VS2005文档重载Equals()和Operator ==(C#编程指南)的指南部分说明
不建议在非不可变类型中覆盖operator ==.
较新的.NET Framework 4文档实现等于和等于运算符的指南(==)省略了该语句,尽管社区内容中的一篇帖子重复了断言并引用了旧文档.
似乎至少对于一些琐碎的可变类来重写Equals()是合理的,例如
public class ImaginaryNumber
{
public double RealPart { get; set; }
public double ImaginaryPart { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在数学中,具有相同实部和相同虚部的两个虚数实际上在测试相等性的时间点是相等的.声明它们不相等是不正确的,如果具有相同RealPart和ImaginaryPart的单独对象未被覆盖Equals(),则会发生这种情况.
另一方面,如果一个重写Equals(),则还应该重写GetHashCode().如果将覆盖Equals()和GetHashCode()的ImaginaryNumber放在HashSet中,并且可变实例更改其值,则不再在HashSet中找到该对象.
MSDN是否不正确删除有关不覆盖Equals()和operator==非不可变类型的指南?
为可变类型重写Equals()是否合理,其中"在现实世界中"所有属性的等价意味着对象本身是相等的(如同ImaginaryNumber)?
如果它是合理的,当对象实例参与HashSet或依赖于GetHashCode()的其他东西没有改变时,如何最好地处理潜在的可变性?
UPDATE
通常,当期望将类型的对象添加到某种类型的集合时,或者当它们的主要目的是存储一组字段或属性时,实现值相等.您可以根据类型中所有字段和属性的比较来定义值相等,或者可以将定义基于子集.但无论是哪种情况,还是在类和结构中,您的实现都应遵循等效的五个保证:
根据MSDN:大多数引用类型不能重载相等运算符,即使它们重写等于.但是,如果要实现旨在具有值语义的引用类型(例如复数类型),则必须覆盖相等运算符.
对于像Customer这样的典型域实体,实现equals方法和相等运算符的最佳实践是什么?
如果两个实体的身份相同,它是否应该实现equals方法返回true?如果实体不是不可变的怎么办?如果两个实体都是新的并且它们的身份具有空值,那该怎么办?那么平等算子怎么样?
我发现我的自我重写Equals()并GetHashCode()经常实现具有相同属性值的业务对象相等的语义.这会导致代码重复写入并且易于维护(属性被添加,并且一个/两个覆盖都不会更新).
代码最终看起来像这样(欢迎对实现的评论):
public override bool Equals(object obj)
{
if (object.ReferenceEquals(this, obj)) return true;
MyDerived other = obj as MyDerived;
if (other == null) return false;
bool baseEquals = base.Equals((MyBase)other);
return (baseEquals &&
this.MyIntProp == other.MyIntProp &&
this.MyStringProp == other.MyStringProp &&
this.MyCollectionProp.IsEquivalentTo(other.MyCollectionProp) && // See http://stackoverflow.com/a/9658866/141172
this.MyContainedClass.Equals(other.MyContainedClass));
}
public override int GetHashCode()
{
int hashOfMyCollectionProp = 0;
// http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/
// BUT... is it worth the extra math given that elem.GetHashCode() should be well-distributed?
int bitSpreader = 31; …Run Code Online (Sandbox Code Playgroud)