views:

201

answers:

4

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

abstract class Foo
{
   ...
}

class SubFoo1 : Foo
{
   ...
}

class SubFoo2 : Foo
{
   ...
}

The dictionary will be delcared: Dictionary<Foo, Bar>

Which classes should be declared as IEquatable? And what should the generic type T be for those declarations? Is this even possible?

A: 

It depends on what you classes stand for. So there is no 'generic' solution to that. If there was, then System.Object would implement IEquatable<object>, as everything inherits from object already anyway. So you could have asked the same question about Object instead of Foo.

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

Short story long, I agree it is difficult to determine what makes objects equal anyway, because even for the same object type, there might be different requirements. When you use a Cache, equality would be determined by an Entity ID of the object. When you use a Do-/Undo-List, you'd need another qualifier because the ID will probably be the same for each object in the list.

Guess I digressed a bit, but I hope I could give you some helpful points. ;-)

herzmeister der welten
A: 

When you start getting inheritance, it indeed gets tricky to choose a T. The base-type is the obvious choice, but I wonder if it isn't more appropriate to just override Equals and GetHashCode.

You might also conclude that such complex scenarios might be poor choices for a key, and use a simpler, more predictable key instead. In particular you want the "hash" to be based on some immutable facet of the type, and the "hash" and "equals" must be compatible. These nuances are very hard to guarantee if the type isn't sealed.

Marc Gravell
A: 

Don't declare anything as IEquatable<T>. It's generally a problem when it comes to inheritance and equality, as Marc says.

Instead, work out what kind of equality you want for the keys in this particular dictionary, and implement IEqualityComparer<Foo>, then pass that into the dictionary constructor.

Usually it's reasonably clear how to compare keys for a specific situation.

Jon Skeet
A: 

You can always specify your own equality comparer in the dictionary constructor. If you don't, the dictionary will look for IEquatable<TKey> so in your case for IEquatable<Foo> therefore you should implement that one.

Bus
But I personaly don't like the IEquatable interface and agree with the other people that you should either override Equals or pass your own comparer.
Bus