从IEqualityComparer<>派生外部类相比覆盖GetHashCode和Equals的优势

5

我需要针对成员变量进行哈希,而不是类本身,这样我就不需要检查引用是否在字典中。如果不覆盖默认值,则它将无法找到相同的Value,但仅在找到完全相同的HashedType实例时返回,因此此代码会失败。

Dictionary.Add(new HashedType(4));
Dictionary.Contains(new HashedType(4)); // fails to find 4

哈希类型的定义:

HashedType
{
   public HashedType(Int32 value) { Value = value); }
   public HashedType(String value) { Value = value); }
   public object Value;
   public void Serialize(Serializer s)
   {
      if (Value.GetType() == typeof(Int32)) 
      {
         s.Set<Int32>(0);
         s.Set<Int32>(Value);
      }
      else 
      {
         s.Set<Int32>(1);
         s.Set<String>(Value);
      }

   }
}

看起来我可以覆盖GetHashCode()和Equals()方法来实现这个目的。

然而,MSDN建议我创建一个单独的类,该类从IEqualityComparer派生,并使用HashedTypeComparer:IEqualityComparer来实例化我的用于HashedType的字典。

为了使这更容易,我从Dictionary中派生并创建了一个新类。

HashedTypeDictionary<U> : Dictionary<T,U> 
{ 
   public HashedTypeDictionary() : base(new  HashedTypeComparer()) { } 
   public bool Equals(HashedType a, HashedType b) { return a.Value == b.Value; }
   publci int GetHashCode(HashedType a) { return a.Value.GetHashCode(); } 
}

这一切似乎都是刻意安排的。

我唯一得到的优势是不需要改变Equals()函数吗?

我的意思是,说真的,我希望Equals()函数只比较那个单一成员。

4个回答

4
这里的想法是object.Equals是该类型的自然相等性(并且GetHashCode应该匹配这种相等性)。当您需要按情况使用不同的相等性时,可以使用IEqualityComparer
例如,考虑一个字符串string。重写的EqualsGetHashCode方法进行区分大小写的比较。但是,如果您想要一个键不区分大小写的字典怎么办?您可以编写一个不区分大小写的IEqualityComparer并在字典的构造函数中传递它。
你的例子听起来好像任何两个HashedType实例如果其成员相等则通常应被视为相等。在这种情况下,我建议重写object.Equalsobject.GetHashCode方法而不编写IEqualityComparer

3
选择一个方法而不是另一个的原因在于,您是希望始终使用特定逻辑来比较给定类型的实例,还是只在这种情况下进行比较。
Equals和GetHashCode提供了“真正的”实现,以确定两个对象是否在逻辑上相等。IEqualityComparer允许您在逐个案例的基础上覆盖默认实现,并分离所有权(可能是控制实体与使用它们的代码的不同方)。

2

想象一下,你并不拥有底层类(即由另一个团队制作或仅以二进制形式提供给你)。你总是可以创建IEqualityComparer。您可能无法更改EqualsGetHashCode的选项...


0
如果大多数时间你希望默认情况下字典的行为是工作的,那么就要重写 GetHashCode 和 Equals 方法。请记住,为了让这个方法能够正常运行,在对象的生命周期内它们不能被更改 - 所以如果它们是基于值来运行的,那么该值应该在构造函数中设置并成为只读属性。
当程序的某个部分需要比较不同的东西时,通常会使用 IEqualityComparer 接口。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接