警告:“...覆盖Object.Equals(对象o),但不覆盖Object.GetHashCode()”
我覆盖了我的类的Equals()以比较类型为Guid的ID值。警告:“...覆盖Object.Equals(对象o),但不覆盖Object.GetHashCode()”
然后Visual Studio中警告说:
...重写Object.Equals(对象o),但 不重写Object.GetHashCode()
所以我随后也推翻它的GetHashCode( )像这样:
public partial class SomeClass
{
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if (obj == null || this.GetType() != obj.GetType()) return false;
return this.Id == ((SomeClass)obj).Id;
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
它似乎工作。 我做得对吗?记得Id是Guid类型的。 我的课是一个实体框架对象吗?
既然你不是在处理一个封闭的类,我建议不要检查类的平等,就像这样。所有子类的SomeClass
应该能够参加Equals
也,所以你可能要改为使用:
if (obj as SomeClass == null) return false;
传统Equals
以这样的方式,两个对象只会是“平等”,如果他们实施在各方面都完全一样。例如,如果您有两个对象表示数据库中的同一对象,但其中一个对象的属性不同于另一对象,则这些对象不会被视为“等于”,并且应该避免在可能的情况下生成相同的“哈希码” 。
在“不等于”一边比错误地调用两个不相等的对象更好。这就是为什么对象的默认实现使用对象本身的内存位置:没有两个对象永远不会被视为“相等”,除非它们是完全相同的对象。所以我会说,除非你想写GetHashCode
和Equals
这样一种方式来检查它们所有属性的相等性,你最好不要覆盖任何一种方法。
如果您有一个数据结构(如HashSet
),您特别想根据ID值确定相等性,则可以为该数据结构提供一个特定的IEqualityComparer
实现。
它看起来对我很正确。每当我做这样的事情时,我通常也执行IEquatable
,以便在相同编译时类型的变量之间进行比较会更有效一些。
public partial class SomeClass : IEquatable<SomeClass>
{
public override bool Equals(Object obj)
{
return Equals(obj as SomeClass);
}
public bool Equals(SomeClass obj)
{
if (obj == null)
return false;
return Id == obj.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
该结构还允许将具有相同Id的更多派生对象比较为等于派生更少的对象。如果这不是所需的行为,那么您将不得不按照问题中的类型进行比较。
if (obj.GetType() != typeof(SomeClass)) return false;
正如其他人所说的那样,在Equals中使用Reflection似乎不太合适。除此之外,让我们专注于GetHashCode。
GetHashCode的主要规则,你不能违反如果两个对象相等,那么它们必须具有相同的散列码。或者,如果两个对象具有不同的哈希代码,则它们的等同方式是,那么它们必须不相等。你的实现在那里看起来不错。
您可以自由违反反面意见。也就是说,如果两个对象具有相同的散列码,那么它们被允许相等或不相等,正如您认为合适的那样。
我假设“Id”是一个不变的属性。如果“Id”可以在对象的生命周期内改变,那么当把对象放在哈希表中时可能会遇到问题。考虑确保只有不可变属性用于计算相等和散列码。
你的实现看起来不错,但是你问这个问题的事实表明你可能没有牢牢掌握构建GetHashCode实现的所有细微因素。一个良好的开始是我的主题文章:
http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/
我已阅读您的文章,并同意您的观点,但我发现自己处于一种只有可变属性的“DataContract”的情况。 '公共字符串日{get;组; ''例如。似乎.NET的自动序列化需要属性是可变的。我的'Equals'方法应根据这些可变属性确定两个对象是否相等。不存在不可变属性。因此,我无法生成安全的'GetHashCode'方法。看起来我的选择是不重写'Equals',或者永远不要将我的'DataContract'放到一个哈希表中...... – crush
@crush:你有第三个选项,它是*当它处于哈希表*。 –
我在你的文章中读到过,但似乎很难确保合同不被破坏。 – crush
你得外观极好回答您的第一个问题:
我有没有做正确吗?
我会回答你的第二个问题
会有问题,我的班是一个实体框架的对象?
是的,它很重要。实体框架在内部使用HashSet
。例如,动态代理使用HashSet
来代表集合导航属性,并且EntityObject
使用EntityCollection
,其在内部依次使用HashSet
。
+1:因此,除非您了解实体框架如何期待它们的行为,否则不要混淆哈希代码。 – StriplingWarrior
我想知道OP实现是否需要根据您的答案进行修改..您说它很重要,为什么它很重要,但不是这意味着实现GetHashCode()的实现者。你能提供更多的信息吗? – Andrew
@Andrew:该信息是在其他答案。 OP的实施不需要任何改变。 –
什么时候子类实例会等于基类实例?该子类将具有其他属性,并且基类在执行比较时不会了解它们。 –
'Equals'目前仅用于处理所有子类将拥有的'Id'。 – recursive
我承认你的逻辑,但正如我在对Eric的评论中指出的,OP的Equals代码直接来自[官方MSDN文档]示例(http://msdn.microsoft.com/en-us/库/ bsc2ak47(v = vs.110)的.aspx)。 (请参阅Point类示例)。 – kmote