I have a class MyClass, and I want to put it as the key to a Dictionary like so:
Dictionary<MyClass, string> dict = new Dictionary<MyClass, string>();
I want to ensure that MyClass is a unique key, and uniqueness is specified by looking at MyClass.UniqueProperty
. My first thought was to overload the ==
operator, but I found that C# does not allow this. Then I found the IComparable interface. Will this do the trick? Or should I overload Object.Equals(obj)?
Dictionary is well prepared for customized equality rules. That's why it has a constructor that takes IEqualityComparer
(https://msdn.microsoft.com/en-us/library/ms132072(v=vs.110).aspx).
Since you only care about equality in the context of the dictionary, IEqualityComparer<MyClass>
is the most straight-forward solution.
Primitive example:
void Main()
{
var dict = new Dictionary<MyClass, string>(new MyClassUniqueIdEqualityComparer());
dict.Add(new UserQuery.MyClass { UniqueId = 1 }, "Hi!");
dict.ContainsKey(new UserQuery.MyClass { UniqueId = 2 }).Dump(); // False
dict.ContainsKey(new UserQuery.MyClass { UniqueId = 1 }).Dump(); // True
}
public class MyClass
{
public int UniqueId { get; set; }
}
public class MyClassUniqueIdEqualityComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass a, MyClass b)
{
return a.UniqueId == b.UniqueId;
}
public int GetHashCode(MyClass a)
{
return a.UniqueId.GetHashCode();
}
}
The main benefit is that the equality rules only apply as defined by the equality comparer. You don't have to ensure proper equality between e.g. a derived class and a base class - it's all just within the contract of the dictionary and the comparer. Since the Equals
and GetHashCode
methods aren't virtual with respect to the dictionary, they allow equality even between different types, as long as they implement the same interface - something you really don't want to do with object.Equals
, IEquatable<T>
and IComparable<T>
.
Is
IComparable
the best way to use to enforce unique keys in Dictionary?
No - IComparable
is for seeing if one object is greater than, equal to, or less than another. It is primarily used in sorting routines. It can be used to see if two objects are equal, but it is not the "best" way.
Or should I overload
Object.Equals(obj)
?
Yes. You can also implement IEquatable<T>
, which is usually trivial if you've already overridden Equals
(and GetHashCode
) appropriately.
Note that the implementaion of GetHashCode
is critical if you're using the object as a hash key. There are many guidelines to follow to implement proper hashing routine, and it's trickier that just comparing equality.
My first thought was to overload the
==
operator, but I found that C# does not allow this.
Well, you can, but it's not appropriate for what you're doing. The ==
operator is conventionally used for reference equality, meaning "do these two variables point to the same instance". Object.Equals
is more appropriate for value equality, meaning "are these two objects really describing the same thing"
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