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.
If we only override equals (Object) method, when we call map.put (g1, “CSE”); it will hash to some bucket location and when we call map.put (g2, “IT”); it will hash to some other bucket location because of different hashcode value as hashCode () method has not been overridden.
The reason why you should override hashcode whenever you override equals is that you need a way to create the same object you want to find. This is particularly useful when you are dealing with collections.
The simplest way to implement GetHashCode () is to use the built-in System.HashCode.Combine () method and pick the properties you want to include. Let it do the work for you. Furthermore, the simplest way to implement Equals () is to use the is operator and compare all the properties.
If two objects are equal according to the equals (Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
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 (i.e. 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 you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With