我覆盖了我班级的Equals()来比较Guid类型的ID值。
然后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类型。 我的类是实体框架对象是否重要?
答案 0 :(得分:31)
正如其他人所说,反对平等的使用似乎很狡猾。抛开这一点,让我们专注于GetHashCode。
如果两个对象相同,那么您必须不违反GetHashCode的主要规则是,那么它们必须具有相同的哈希码。或者,如果两个对象具有不同的哈希码,则表示的等效方式则必须是不相等的。您的实现在那里看起来很好。
你可以自由地违反反过来。也就是说,如果两个对象具有相同的哈希码,则允许它们相等或不相等,如您所见。
我假设“Id”是一个不可变的属性。如果“Id”可以在对象的生命周期内更改,那么将对象放入哈希表时可能会出现问题。考虑确保在计算相等性和哈希码时只使用不可变属性。
您的实现看起来不错,但您提出问题的事实表明您可能无法掌握构建GetHashCode实现的所有细微因素。一个好的起点是我关于这个主题的文章:
http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/
答案 1 :(得分:8)
对我而言看起来是正确的。每当我做这样的事情时,我通常也会实现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;
答案 2 :(得分:6)
由于您没有处理密封类,我建议不要像this.GetType() != obj.GetType()
那样检查类的相等性。 SomeClass
的任何子类也应该能够参与Equals
,因此您可能希望使用此类:
if (obj as SomeClass == null) return false;
答案 3 :(得分:5)
传统上Equals
的实现方式是,如果两个对象在各个方面完全相同,那么它们只是“等于”。例如,如果有两个对象代表数据库中的同一个对象,但是其中一个对象具有不同的Name
属性,则对象不会被视为“等于”,并且应该避免生成相同的对象。哈希码“如果可能的话。
最好在“不平等”方面犯错,而不是冒险调用两个不相等的对象。这就是对象的默认实现使用对象本身的内存位置的原因:除非它们是完全相同的对象,否则不会将两个对象视为“相等”。所以我要说除非你想以这样的方式写GetHashCode
和Equals
来检查它们所有属性的相等性,否则你最好不要覆盖任何一种方法。
如果您有一个数据结构(如HashSet
),您特别希望根据ID值确定相等性,则可以为该数据结构提供特定的IEqualityComparer
实现。
答案 4 :(得分:5)
你的第一个问题得到了很好的答案:
我做得对吗?
我会回答你的第二个问题
我的类是实体框架对象是否重要?
是的,这很重要。实体框架在内部使用HashSet
。例如,动态代理使用HashSet
表示集合导航属性,使用EntityObject
使用EntityCollection
,然后在内部使用HashSet
。