C # dictionary uniqueness for sibling classes using IEquatable <T>

I would like to keep the insances of two classes in a dictionary structure and use IEquatable to determine the uniqueness of these instances. Both of these classes have a (abstract) base class. Consider the following classes:

abstract class Foo
{
   ...
}

class SubFoo1 : Foo
{
   ...
}

class SubFoo2 : Foo
{
   ...
}

      

The dictionary will share: Dictionary<Foo, Bar>

Which classes should be declared as IEquatable? And what should be the generic T type for these declarations? Is it possible?

+2


a source to share


5 answers


Don't declare anything as IEquatable<T>

. This is usually a problem when it comes to inheritance and equality, as Mark says.

Instead, define what kind of equality you want to use for the keys in that particular dictionary and implement IEqualityComparer<Foo>

, then pass that to the dictionary constructor.



It is usually pretty clear how to compare keys for a given situation.

+4


a source


It depends on what your class means. So there is no "general" solution for this. If it did, it System.Object

would do it IEquatable<object>

, because everything inherits from object

already in any case. Therefore, you might have asked the same question about object

instead Foo

.

In short, it depends on what you want to achieve with your class hierarchy.



Short story, I agree that it is difficult to define what makes objects the same, because even for the same type of object there may be different requirements. When you use a cache, equality will be determined by the object id of the object. When you use Do- / Undo-List you need a different qualifier because the ID will probably be the same for every object in the list.

I think I digress a little, but I hope I can give you some useful points .; -)

0


a source


When you start getting inheritance, it really becomes difficult to choose T

. The base type is the obvious choice, but I'm wondering if it's not appropriate to just override Equals

and GetHashCode

.

You might also conclude that such complex scenarios might be a bad choice for a key and instead use a simpler and more predictable key. In particular, you want the "hash" to be based on some kind of immutable type face, and the "hash" and "equal" must be compatible. These nuances are very difficult to guarantee if the type is not sealed

.

0


a source


You can always specify your own comparison matcher in the dictionary constructor. If you don't, the dictionary will search IEquatable<TKey>

, so in your case for IEquatable<Foo>

, so you have to implement it.

0


a source


Inherited classes almost never implement IEquatable<T>

. For any type, T

every object that implements IEquatable<T>

must do the semantics IEquatable<T>.Equals

match the semantics Object.Equals

. If the class implements IEquatable<Foo>

for some Foo

, and the derived class changes semantics Object.Equals

but does not override IEquatable<Foo>.Equals

, the only way the latter's semantics will match the former would be if the implementation interface just calls the virtual Object.Equals

; if the interface just passes its argument Object.Equals

, there is no benefit to implementing it.

0


a source







All Articles