简体   繁体   中英

Advantage of deriving external class from IEqualityComparer<> over overriding GetHashCode and Equals

I'm need to hash against a member variable instead of the class, so I don't check if the reference is in the dictionary. Without overriding the defaults, it won't find an identical Value , but only return if it finds the same exact instance of HashedType , such that this code fails.

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

Definition of HashedType:

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);
      }

   }
}

It looks like I can override GetHashCode() and Equals() to do this for me.

However, MSDN recommends I create a separate class that I derive from IEqualityComparer and instantiate my dictionaries used HashedType with the HashedTypeComparer : IEqualityComparer.

To help make this easier, I've derived from Dictionary and created

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(); } 
}

This all seems contrived.

Is the only advantage I get is not changing the Equals()?

I mean, really speaking, I would want Equals to compare against that single member anyway.

The idea is that object.Equals is the natural equality for that type (and GetHashCode should match that idea of equality). IEqualityComparer is used when you want a different equality on a case-by-case basis.

Consider for example, a string . The overridden Equals & GetHashCode methods do case-sensitive comparisons. But what if you want a dictionary where the keys are not case-sensitive? You write an IEqualityComparer that is not case-sensitive and pass it in the constructor of the dictionary.

Your examples sounds like any two instances of HashedType are to be normally treated as equal if their members are equal. In that case I'd recommend overriding the object.Equals and object.GetHashCode methods and not writing a IEqualityComparer .

The reason you would choose one over the other is whether you always want instances of a given type to be compared using a certain logic, or only in this one situation.

Equals and GetHashCode provide the "true" implementation of whether two objects are logically equal . IEqualityComparer allows you to override that in a case-by-case basis , and to separate ownership (it might be different parties who control the entities versus the code using them).

Imagine, for a moment, that you don't own the underlying class (ie it's produced by another team, or only given to you as a binary). You always can create the IEqualityComparer . You might not have the option of changing Equals and GetHashCode ...

If the majority of the time you want the Dictionary behavior to work by default override GetHashCode and Equals. Bear in mind for this to work they must never change during the lifecycle of the object - so if they are running off Value then Value should be set in the constructor and a read-only property.

IEqualityComparer is really used for when you want to compare things differently in one section of your program.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM