Was IEqualityComparer<T> introduced for the following reasons? - c#

1) Are the reasons why IEqualityComparer<T> was introduced:
a) so we would be able to compare objects (of particular type) for equality in as many different ways as needed
b) and by having a standard interface for implementing a custom equality comparison, chances are that much greater that third party classes will accept this interface as a parameter and by that allow us to inject into these classes equality comparison behavior via objects implementing IEqualityComparer<T>
2) I assume IEqualityComparer<T> should not be implemented on type T that we're trying to compare for equality, but instead we should implement it on helper class(es)?
Thank you

I'm doubtful that anyone here will be able to answer with any authority the reason that the interface was introduced (my guess--and that's all it is--would be to support one of the generic set types like Dictionary<TKey, TValue> or HashSet<T>), but its purpose is clear:
Defines methods to support the comparison of objects for equality.
If you combine this with the fact you can have multiple types implementing this interface (see StringComparer), then the answer to question a is yes.
The reason for this is threefold:
Operators (in this case, ==) are not polymorphic; if the type is upcasted to a higher level than where the type-specific comparison logic is defined, then you'll end up performing a reference comparison rather than using the logic within the == operator.
Equals() requires at least one valid reference and can provide different logic depending on whether it's called on the first or second value (one could be more derived and override the logic of the other).
Lastly and most importantly, the comparison logic provided by the type may not be what the user is after. For example, strings (in C#) are case sensitive when compared using == or Equals. This means that any container (like Dictionary<string, T> or HashSet<string>) would be case-sensitive. Allowing the user to provide another type that implements IEqualityComparer<string> means that the user can use whatever logic they like to determine if one string equals the other, including ignoring case.
As for question b, probably, though I wouldn't be surprised if this wasn't high on the list of priorities.
For your final question, I'd say that's generally true. While there's nothing stopping you from doing so, it is confusing to think that type T would provide custom comparison logic that is different from that provided on type T just because it's referenced as an IEqualiltyComparer<T>.

agreed on a and b
"should not be" is always a normative question and rarely a good metric. You do what works without getting into trouble. (Pragmatic Programmer). The fact that you can implement the interface statefull, stateless and in any which way, makes it possible to implement (alternative) comparers for all types, including value types, enums, sealed types, even abstract types; In essence it is a Strategy pattern

Sometimes there's a natural equality comparison for a type, in which case it should implement IEquatable<T>, not IEqualityComparer<T>. At other times, there are multiple possible ways of comparing objects for equality - so it makes sense to implement IEqualityComparer<T> then. It allows hash tables (and sets etc) to work in a flexible way.

Related

C# Generic Collections, IComparer, IComparable and IEquatable

I am working on a C# project where I make heavy use of interfaces, and the System.Collections.Immutable library. I wish to sort implementations of one of my interfaces in an immutable set, ImmutableSortedSet<IMyInterface>.
In Java this is a straightforward matter of implementing Comparable<IMyInterface> and overriding the equals and hash code functions. I found a similar interface in .net IComparable<IMyInterface> but it warns implementers that if they choose to implement the interface, then they should also override the comparison operators (<,>,<=,>=), as well as implement IEquatable<IMyInterface>. IEquatable<T> warns implementers that they should override the equals and hash code functions, as well as the '==' and '!=' operators.
Now I'm having second thoughts about implementing IComparable<T>, I'm not creating a new primitive type here, I just want to provide a convenient sorting algorithm for a complex reference type. Furthermore, there seems to be a certain problem in C# with overriding operators at the interface level, I am therefore leaning towards using a separate IComparer<IMyInterface> implementation.
What really raised my eyebrows though was hearing this:
The IEquatable<T> interface is used by generic collection objects such as Dictionary<TKey, TValue>, List<T>, and LinkedList<T> when testing for equality in such methods as Contains, IndexOf, LastIndexOf, and Remove. It should be implemented for any object that might be stored in a generic collection.
Does this combined with
If you implement IEquatable<T>, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable<T>.Equals method. If you do override Object.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. In addition, you should overload the op_Equality and op_Inequality operators. This ensures that all tests for equality return consistent results.
Mean that I am expected to override both '==' and '!=' operators for any type that I want to store inside a generic collection??
IComparable<T> is the preferred mechanism to provide comparison support for sorting. The advice of implementing the comparison operators doesn't make a lot of sense for most types, and they could not be utilized by generic collections anyway. You should also implement IEquatable<T>, override GetHashCode(), and override object.Equals to delegate to IEquatable<T>.Equals.
In general, whenever I implement IComparable<T>, I also implement the non-generic IComparable, but I implement IComparable.CompareTo explicitly such that it is normally hidden.
As you already noticed, if you need sorting, you can pass IComparer<T> implementation and your type doesn't have to implement IComparable<T>. In some cases it's easier and in some cases it's the only way to go, e.g. when you want the same type to be sorted differently in different situations. You can just pass different IComparer<T> implementations in that case.
About IEquatable<T> related quotes. For most situations overriding Equals and GetHashCode is enough. It will make your type work with List<T>.Contains and similar methods. It will also allow you to use your type as key in Dictionary<TKey, TValue> and store it in HashSet<T>. That's because all these cases use EqualityComparer<T>.Default when comparer is not specified.
The way EqualityComparer<T>.Default works can be found here. As you can see it verifies that your type implements IEquatable<T>, but if it doesn't creates an instance of ObjectEqualityComparer<T>, which will just use Equals and GetHashCode methods to verify equality.

Difference between .Equals, IComparable and IComparer

Can someone please explain with example that I can understand about the difference between .Equals, IComparable and IComparer.
I was asked this in an interview.
Well first off, on the surface, Equals is a method (present in every object), while IComparable and IComparer are interfaces.
Equals is present in any class and can be overriden to provide equality testing depending on the context of the class (it's a good practice to override GetHashCode as well). By default it just tests if objects are equal in memory which is not very useful. Equals (and GetHashCode) are usually given a different implementation in the context of searching or hashing.
Implementing IComparable is a more fine-grain way of comparison, as it provides the CompareTo method, which is a greater-than/less-than comparison as opposed to Equals which is simply a is-equal-or-not comparison. For example a binary search tree structure could benefit from this method.
IComparer is similar to IComparable, except that it works from the outside. It allows you to define a "neutral" object that is used for comparing two other objects without modifying them directly, which you need to do with IComparable.
Equals is a method, when 2 other are interfaces. So look like the biggest difference.
More seriously - #ChrisSinclair gave you an answer in comments...
Equals returns true/false if the two objects are equal (or the same reference depending on your implementation) IComparable/IComparer: difference between IComparable and IComparer
.Equals() gives your class a way to test for equality against all other possible objects. This can be considered as the fallback for object equality. So this answers the question am I equivalent to the object passed in as a param.
IComparable provides for a way of comparing objects which can be ordered, possible uses include sorting. Implementing this interface puts the ordering logic into your class.
IComparer does pretty much the same as IComparable except the logic is contained in separate class.

Interface vs internal variable vs inheritance dictionary

I have read
When should I choose inheritance over an interface when designing C# class libraries?
I believe I understand is-a vs must-do relationship. Having said all that here is my dilemma.
I want to implement a Collection of key value pairs most likely object. I need to add to the add and remove events only to do validation, check for duplication and some tracking stuff.
If I implement IDictionary it seems that it is a bit of an over kill to implement all the Idictionary<>, ICollection<>, IEnumerable<>, and IEnumerable. Yes most of them are one liners.
It is not recommended to inherit from Dictionary as it was never meant to be extended, shadowing the Add and remove.
Finally I can just implement a private variable and then expose the methods I want or need for the project
Any suggestions on the direction to go?
You should use composition and encapsulate a dictionary inside your class (the private variable option). This way, you only expose to the outside world the operations that make sense for your object and the fact that you use a dictionary is a mere implementation detail.
You should only implement IDictionary<,> or inherit from Dictionary<,> if your class is a generic dictionary with some special characterists.
The simplest approach would be to implement the IDictionary as an instance variable and wrap the Add and Remove methods in Add and Remove methods in your class that perform validation before adding or removing the object to or from the dictionary.
Inheritance is for when you need to inherit implementation. Otherwise, if you want to inherit interface, bit not implementation, uses interfaces.
I would suggest perhaps designing some of your own dictionary-ish interfaces which include the functionality you're interested in. Among other things, I would suggest having some interfaces which exist purely for reading the interface, and some which allow read-write access. Among other things, if you have a read-only interface, methods which don't care whether a particular dictionary is mutable or immutable will be able to use an IReadableDict (implemented by both mutable and immutable dictionaries) while routines that require either that a dictionary be mutable or that it be immutable will be able to specify that. Further, segregating out some other interfaces will allow maximum possibilities for covariance and contravariance. For example, code which is expecting an IReadableDict<String, Animal> could be perfectly happy with a Dict<String, Cat> even though code which was expecting an IReadWriteDict<String, Animal> would not be able to accept an Dict<String, Cat>. Likewise, code which only needs to know the count of a dictionary could accept a non-generic ICountable which exposes a Count method, and code which only needs to know whether a certain key exists could accept a non-generic IQueryExistence (note that one can perfectly legitimately check whether a Dict<Cat, PurrVolume> contains a particular instance of Dog; the answer will be 'no', but the question is valid).

should all c# classes implement Equals and GetHashCode?

should all c# classes override Equals and GetHashCode? For correctness
No, they already do.
Whether you have to override them, is up to how it will be used. In most cases, it is not needed.
All classes already inherit these methods from the base class, System.Object.
You can choose to override the methods in derived classes if you need to be able to compare two instances of an object beyond simple reference equality, otherwise it's not necessary.
Remember, however, that if you choose to override one of them, you also need to override the other in order to ensure that Hashtables and dictionary keys, among other things, work properly with you derived class. The GetHashCode method needs to reflect the same logic as the Equals method. See here for more explanations and examples:
http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx
and
http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx
All classes to inherit this from the System.Object.
If you need to provide a specific Equals or GetHashCode for a class then you should override the methods in your classes. Otherwise just leave them..
http://msdn.microsoft.com/en-us/library/system.object.gethashcode(v=VS.71).aspx
Maybe not all, but all classes that will be put into a some kind of bag (IList, ICollection, IDictionary, Hashset, etc.) and need some simple method to differentiate them (just think about Sort(), Contains(), BinarySearch(), etc.).
If you use a class that way you should definitely implement them correct.
When you override Equals, basically.
When you want to provide a different
idea of equality than simple reference
equality.
String is a good example of this - two
strings are equal (under a simple
Equals call) if they represent the
same sequence of characters. The hash
code reflects this, such that if two
strings are equal they will have the
same hash code. (The reverse isn't
necessarily true - two unequal strings
can have the same hash code, but it's
unlikely.)
(Strings are tricky in other ways,
mind you - there are lots of different
ideas of equality based on culture and
casing, but String.Equals just looks
at the UTF-16 code points which make
up the string, and compares them in
the simplest conceivable fashion.)
by Jon Skeet

Why was IEquatable T not made contravariant in T for C# 4.0?

IEquatable<T> could have been declared to be contravariant in T, since it only uses T in an input position (or, equivalently, U being a subtype of T should imply that IEquatable<T> is [a subtype of] IEquatable<U>).
So, why did the BCL team not annotate it (for C# 4.0) with the 'in' keyword, as they did with many other generic interfaces (like the entirely analogous IComparable)?
I think this is mainly for a philosophical reason rather than a technical limitation–as it's perfectly possible to simply annotate the interface. IEquatable<T> is meant to compare objects of the same type for exact equality. An instance of a superclass is not usually considered equal to an instance of a subclass. Equality in this sense implies type equality too. This is a bit different from IComparable<in T>. It can be sensible to define a relative sort order across different types.
To quote MSDN page on IEquatable<T>:
Notes to Implementers:
Replace the type parameter of the IEquatable<T> interface with the type that is implementing this interface.
This sentence further demonstrates the fact that IEquatable<T> is meant to work between instances of a single concrete type.
Inheritable types should generally not implement IEquatable<T>. If IEquatable<T> included a GetHashCode() method, one could define the semantics of IEquatable<T> to say that items should compare equal when examined as T's. Unfortunately, the fact that IEquatable<T> is bound to the same hash code as Object.Equals means that in general IEquatable<T> has to implement essentially the same semantics as Object.Equals.
Consequently, if an implementation of IEquatable<BaseClass> does anything other than call Object.Equals within it, a derived class which overrides Object.Equals and GetHashCode() and does not re-implement IEquatable<BaseClass> will end up with a broken implementation of that interface; an implementation of IEquatable<BaseClass> which simply calls Object.Equals will work just fine, even in that scenario, but will offer no real advantage over a class which doesn't implement IEquatable<T>.
Given that inheritable classes shouldn't be implementing IEquatable<T> in the first place, the notion of covariance is not relevant to proper implementations of the interface.

Categories

Resources