C# GetHashCode/Equals override not called
我面临一个GetHashCode和Equals的问题,我已经为一个类重写了它。我使用操作符==来验证两者是否相等,我希望这将同时调用getHashCode和equals,如果它们的哈希代码相同,以验证它们是否确实相等。
但令我惊讶的是,两人都没有被召唤,平等测试的结果是错误的(尽管事实上应该是正确的)。
重写代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class User : ActiveRecordBase<User>
[...]
public override int GetHashCode()
{
return Id;
}
public override bool Equals(object obj)
{
User user = (User)obj;
if (user == null)
{
return false;
}
return user.Id == Id;
}
} |
平等检查:
1 2
| if (x == y) // x and y are both of the same User class
// I'd expect this test to call both GetHashCode and Equals |
- 如果==实际上调用了您的Equals方法,那么它将导致堆栈溢出,因为它在对象上使用==运算符…
- 您所显示的代码中没有任何内容表明需要调用GetHashCode()。仅当使用对象作为集合的键时才调用。
操作员==与.GetHashCode()或.Equals()完全分离。
您可能对Microsoft有关重载equals()和operator==的指导原则感兴趣。
简短的版本是:使用.Equals()实现相等比较。使用操作符==进行身份比较,或者如果要创建不可变类型(其中每个相同的实例都可以被视为有效相同)。另外,.Equals()是一个虚拟方法,可以被子类重写,但是操作符==取决于使用它的表达式的编译时类型。
最后,为了保持一致,在任何时候执行.Equals()都可以执行.GetHashCode()。超载操作员!=,任何时候超载操作员==。
- 我的物品是可变的。我希望调用==运算符实际上会调用equals方法,我以前见过这种方法,但我不理解为什么它现在不工作,以前也工作过…
- @tomzx:==操作符从不调用.Equals()方法,除非您重载它来这样做。
- @Daniel Your Advice re"=="不正确。微软一贯认为,如果你想进行身份比较,你必须使用"referenceequals"。例如,考虑字符串。如果使用字符串生成器生成两个内容相同但地址不同的字符串,则"=="将返回true(相等比较),但referenceEquals将返回false。="通常被视为相等比较,并且通常被实现为执行类的相等操作。
- 简单测试:referenceEquals(new string("abc")、new string("abc")返回false。但是((new string("abc"))==(new string("abc"))返回true。因此"=="是一个相等比较,而不是一个身份比较。如果一个类没有指定"==",那么默认行为就是使用referenceEquals。还要考虑值对象,它显然对"=="执行相等测试。
- @toolmakersteve:从我的答案中的链接:"当一个类型是不可变的,也就是说,不能更改实例中包含的数据时,重载操作符==比较值相等而不是引用相等可能很有用,因为作为不可变的对象,只要它们具有相同的值,就可以认为它们是相同的。在非不可变类型中重写运算符==,这不是一个好主意。"——这意味着我认为==只应在相等和标识可以安全地冲突的地方(即,与不可变的值类型类似的值)表现得像相等运算符。
- @丹尼尔,我关心的是你的回答是"使用操作符==进行身份比较"。在.NET中,"标识"具有特定的含义。在引擎盖下,它意味着两个相同的指针指向相同的内存位置。这就是引用等于。msdn.microsoft.com/en-us/library/vstudio/dd183759.aspx如果您使用的"身份"一词与此不同,则可能会使人困惑。你所讨论的不是同一性,而是等价性。
- 具体来说,两个内容相同(但对象不同;内存中的位置不同)的不可变对象不具有"相同的标识",因为.NET定义了这个术语。即使您是正确的,它们是相同的;用一个替换另一个不应该改变程序的结果,如果它们是不可变的。
- @工具制造商:啊,我现在明白你的困惑了。我的句子并不是试图定义"身份比较"的含义,您在.NET中正确地指出,它有一个既定的含义,而是提供使用==的两个可能原因:用于身份比较,或用于不可变的对象。
也许在您的User类中再添加一个方法。
1 2 3 4 5 6
| public virtual bool Equals(User other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return other.Id == Id;
} |