What's the recommended best practice for using IEqualityComparer<T>? - c#

I'm looking for real world best practices, how other people might have implemented solutions with complex domains.

Any time you consider using an IEqualityComparer<T>, pause to think if the class could be made to implement IEquatable<T> instead. If a Product should always be compared by ID, just define it to be equated as such so you can use the default comparer.
That said, there are still a few of reasons you might want a custom comparer:
If there are multiple ways instances of a class could be considered equal. The best example of this is a string, for which the framework provides six different comparers in StringComparer.
If the class is defined in such a way that you can't define it as IEquatable<T>. This would include classes defined by others and classes generated by the compiler (specifically anonymous types, which use a property-wise comparison by default).
If you do decide you need a comparer, you can certainly use a generalized comparer (see DMenT's answer), but if you need to reuse that logic you should encapsulate it in a dedicated class. You could even declare it by inheriting from the generic base:
class ProductByIdComparer : GenericEqualityComparer<ShopByProduct>
{
public ProductByIdComparer()
: base((x, y) => x.ProductId == y.ProductId, z => z.ProductId)
{ }
}
As far as use, you should take advantage of comparers when possible. For example, rather than calling ToLower() on every string used as a dictionary key (logic for which will be strewn across your app), you should declare the dictionary to use a case-insensitive StringComparer. The same goes for the LINQ operators that accept a comparer. But again, always consider if the equatable behavior that should be intrinsic to the class rather than defined externally.

I did the following, I'm not sure if it is real-world best practice, but it worked fine for me. :)
public class GenericEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, Boolean> _comparer;
private Func<T, int> _hashCodeEvaluator;
public GenericEqualityComparer(Func<T, T, Boolean> comparer)
{
_comparer = comparer;
}
public GenericEqualityComparer(Func<T, T, Boolean> comparer, Func<T, int> hashCodeEvaluator)
{
_comparer = comparer;
_hashCodeEvaluator = hashCodeEvaluator;
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
return _comparer(x, y);
}
public int GetHashCode(T obj)
{
if(obj == null) {
throw new ArgumentNullException("obj");
}
if(_hashCodeEvaluator == null) {
return 0;
}
return _hashCodeEvaluator(obj);
}
#endregion
}
Then you can use it in your collections.
var comparer = new GenericEqualityComparer<ShopByProduct>((x, y) => x.ProductId == y.ProductId);
var current = SelectAll().Where(p => p.ShopByGroup == group).ToList();
var toDelete = current.Except(products, comparer);
var toAdd = products.Except(current, comparer);
If you need to support custom GetHashCode() functionality, use the alternative constructor to provide a lambda to do the alternative calculation:
var comparer = new GenericEqualityComparer<ShopByProduct>(
(x, y) => { return x.ProductId == y.ProductId; },
(x) => { return x.Product.GetHashCode()}
);
I hope this helps. =)

See this post for (better) alternatives: Wrap a delegate in an IEqualityComparer
Scroll down to the part on KeyEqualityComparer and especially the part on the importance of GetHashCode. There is a whole discussion on why obj.GetHashCode(); (as suggested by DMenT's post) is wrong and should just return 0 instead.

This is what MSDN has to say about IEqualityComparer (non-generic):
This interface allows the implementation of customized equality comparison for collections. That is, you can create your own definition of equality, and specify that this definition be used with a collection type that accepts the IEqualityComparer interface. In the .NET Framework, constructors of the Hashtable, NameValueCollection, and OrderedDictionary collection types accept this interface.
This interface supports only equality comparisons. Customization of comparisons for sorting and ordering is provided by the IComparer interface.
It looks like the generic version of this interface performs the same function but is used for Dictionary<(Of <(TKey, TValue>)>) collections.
As far as best practices around using this interface for your own purposes. I would say that the best practice would be to use it when you are deriving or implementing a class that has similar functionality to the above mentioned .NET framework collections and where you want to add the same capability to your own collections. This will ensure that you are consistent with how the .NET framework uses the interface.
In other words support the use of this interface if you are developing a custom collection and you want to allow your consumers to control equality which is used in a number of LINQ and collection related methods (eg. Sort).

I would say that the best use would be when you need to plug in different equality rules for a certain algorithm. Much in the same way that a sorting algorithm might accept an IComparer<T>, a finding algorithm might accept an IEqualityComparer<T>

The list uses this interface alot, so you can say a.Substract(b) or other of these nice functions.
Just remember: If you're objects don't return the same Hashcode, the Equals is not called.

Related

Anonymous inner classes in C#?

Is there something like anonymous inner classes (used in Java) in C#?
I explain what I would use it for by example: I'm declaring and initializing field of type IDictionary<Person, Account> and I need to write custom IEqualityComparer<Person>. That is because I want two Persons to be treated as equal by the IDictionary when they have equal names and IDs (not only IDs as it is by default). I will not need this IEqualityComparer<Person> anywhere else in the code.
So I do I have to declare new class that implements IEqualityComparer<Person> to do this ? In Java I would use anonymous class, something like this(this is mixed C#-Java syntax, just to show what functionality I'm looking for):
IDictionry<Person, Account> myDict = new Dictionary<Person, Account>(
new IEqualityComparer<Person>(){
public bool Equals(Person a, Person b){
return a.Id == b.Id && a.Name == b.Name;
}
public int GetHashCode(Person p){
return p.Id.GetHashCode() * p.Name.GetHashCode();
}
});
Is something like this in C# ? I'm too lazy to write new class every time I need something like this.
Note: This is syntax question. I know how to write it, but I want to know if it's possible to make the code shorter.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EDIT: How do you yourself code similar cases ? Do you create new class to implement the interface or what do you do ? Maybe you have some trick that I might like.
EDIT What about future support for anonymous classes like those in Java ? Have you heard something about it ?
EDIT: Well I see I'll have to provide my actual code - not just an example. That's because I don't know if it's going to work with Jon's Skeet's solution.
The actual reason why I don't just implement Equals(object) and GetHashCode in the class itself is, that it's class(entity) generated by E-R framework from model diagram. If I implemented it in class itself my code would be deleted from the class(entity) every time I update the model from database (using "update from database" feature). The class is actually called Font not Person. It has this properities:
Id: int
FamilyName:string
Size:int
Bold:bool
Italic:bool
Underlined:bool
Striked:bool
Foreground:Color
Where Color is another class (entity) generated from database.
This are properties of Color:
Id:int
Alpha:byte
Red:byte
Green:byte
Blue:byte
So I cannot modify Font, neither Color (if I don't want to rewrite those changes over and over again every time I change database) What I want is to have this Dictionary:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>(new SomeEqualityComparer());
And the comparer SomeEqualityComparer should ensure that two Fonts would be considered equal if and only if all the properties listed above(except Id) are equal. In the case of last property Foreground two Colors are considered equal when all their properties(except Id) are equal.
Now if I use solution that Jon Skeet has kindly recommended me, I'm not sure if that can be ensured.
If I used something like:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>(ProjectionEqualityComparer<Font>.Create
(f => new { f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked, f.Foreground});
I'd guess that anonymous types call Equals(object) on all properties when their Equals(object) is called. However as I cannot override Color's Equals(object) it would not compare Colors as I want (using all properties except Id) so also the equality of Fonts would be tested incorrectly. Am I right ?
I have a ProjectionEqualityComparer class you could use in MiscUtil. You'd use code like this:
IEqualityComparer<Person> comparer = ProjectionEqualityComparer<Person>.Create
(p => new { p.Name, p.Id });
Thhat uses the fact that anonymous types have appropriate equality notions built in - when the ProjectionEqualityComparer is asked to compare two people for equality, it will project each to the anonymous type, and compare those instances. Likewise when it's asked for a hashcode, it will perform the projection and ask that for its hash code.
EDIT: To tackle your colour problem, you're right: if Color doesn't override Equals/GetHashCode in the way that you want, you can't use it directly. However, you can do this instead:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>
(ProjectionEqualityComparer<Font>.Create(f => new {
f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked,
f.Foreground.Alpha, f.Foreground.Red, f.Foreground.Green,
f.Foreground.Blue});
If you're able to modify the Color type in terms of properties, it would be simpler if you could give it an ARGB property generated from the others, so you could write:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>
(ProjectionEqualityComparer<Font>.Create(f => new {
f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked,
f.Foreground.ARGB });
That's pretty ugly, but it should work...
In your last edit you mention that the reason that you don't implement Equals and GetHashCode is because the code for your classes is auto-generated and you don't want to have to re-implement that code each time you regenerate the code.
That's one of the scenarios for which partial classes were introduced in C#
A lot of code generation tools will generate classes with the partial keyword to allow you to take advantage of that feature. Check if the classes that are being generated for your code are partial.
In a separate file (or files) that won't be overwritten when you regenerate the code, within the same assembly, you could have something like the following:
partial class Font
{
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
// ...
}
}
partial class Color
{
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
// ...
}
}
No there isn't. There are anonymous types e.g.
var MyType = new { id=1, name="john", dept = "sales" };
but they are very limited, and only contain read only properties and no methods.
The literal answer is that no, C# doesn't have anonymous inner classes, because Java added those to get around its lack of first-class functions, which C# does have. More specifically, to solve your problem, you can just implement IEquatable<Person> on your Person class, and then IDictionary will use that automatically. That's the most common solution to this problem and works as long as your OK with the process for comparing Persons being baked into that class.
If you want the comparison/equality logic to not be tied directly to Person, most collections in .NET allow you to pass in a Comparison<T> object (which is a delegate, not an interface), letting you do nice in-place sorting logic. For example, to sort a list of people by name, you could do:
List<Person> people = ...
people.Sort((x, y) => x.Name.CompareTo(x.y));
Unfortunately, Dictionary doesn't have something similar to an equality function. In .NET 4.0, the stock answer seems to be to override EqualityComparer<T>:
public class PersonComparer : EqualityComparer<Person>
{
public override bool Equals(Person a, Person b)
{
return a.Id == b.Id && a.Name == b.Name;
}
}
Having to define a new class each time you need to compare, though, is a chore. What I'd do is make a generic one that takes a function:
public class Equality<T> : EqualityComparer<T>
{
public Equality(Func<T, T, bool> comparer)
{
this.comparer = comparer;
}
public override bool Equals(T a, T b)
{
return comparer(a, b);
}
private Func<T, T, bool> comparer;
}
Add a little helper class:
public static class Equality
{
public static Equality<T> Create<T>(Func<T, T, bool> comparer)
{
return new Equality<T>(comparer);
}
}
And then your solution becomes:
IDictionary<Person, Account> myDict = new Dictionary<Person, Account>(
Equality.Create((a, b) => a.Id == b.Id && a.Name == b.Name);
Even shorter than it would be in Java.
The closest you're going to get is anonymous types like you'd see in a LINQ expression. A short example from the link:
var v = new { Amount = 108, Message = "Hello" };
Definitely not what you're looking for. I haven't heard of future support for anonymous classes in C# either.
You could define the implementation of the interface in one place, 1 class, map the interface to your desired implementation class in your favorite IOC framework and not have to think about instantiating a 1-time-use anonymous implementation at all.
No, as of the time this question was originally written (C# 3.0), there is not.

Advantages/Disadvantages of different implementations for Comparing Objects

This questions involves 2 different implementations of essentially the same code.
First, using delegate to create a Comparison method that can be used as a parameter when sorting a collection of objects:
class Foo
{
public static Comparison<Foo> BarComparison = delegate(Foo foo1, Foo foo2)
{
return foo1.Bar.CompareTo(foo2.Bar);
};
}
I use the above when I want to have a way of sorting a collection of Foo objects in a different way than my CompareTo function offers. For example:
List<Foo> fooList = new List<Foo>();
fooList.Sort(BarComparison);
Second, using IComparer:
public class BarComparer : IComparer<Foo>
{
public int Compare(Foo foo1, Foo foo2)
{
return foo1.Bar.CompareTo(foo2.Bar);
}
}
I use the above when I want to do a binary search for a Foo object in a collection of Foo objects. For example:
BarComparer comparer = new BarComparer();
List<Foo> fooList = new List<Foo>();
Foo foo = new Foo();
int index = fooList.BinarySearch(foo, comparer);
My questions are:
What are the advantages and disadvantages of each of these implementations?
What are some more ways to take advantage of each of these implementations?
Is there a way to combine these implementations in such a way that I do not need to duplicate the code?
Can I achieve both a binary search and an alternative collection sort using only 1 of these implementations?
There really is no advantage to either option in terms of performance. It's really a matter of convenience and code maintainability. Choose the option you prefer. That being said, the methods in question limit your choices slightly.
You can use the IComparer<T> interface for List<T>.Sort, which would allow you to not duplicate code.
Unfortunately, BinarySearch does not implement an option using a Comparison<T>, so you cannot use a Comparison<T> delegate for that method (at least not directly).
If you really wanted to use Comparison<T> for both, you could make a generic IComparer<T> implementation that took a Comparison<T> delegate in its constructor, and implemented IComparer<T>.
public class ComparisonComparer<T> : IComparer<T>
{
private Comparison<T> method;
public ComparisonComparer(Comparison<T> comparison)
{
this.method = comparison;
}
public int Compare(T arg1, T arg2)
{
return method(arg1, arg2);
}
}
Probably the biggest advantage to accepting a Comparison<T> as opposed to an IComparer<T> is the ability to write anonymous methods. If I have, let's say, a List<MyClass>, where MyClass contains an ID property that should be used for sorting, I can write:
myList.Sort((c1, c2) => c1.ID.CompareTo(c2.ID));
Which is a lot more convenient than having to write an entire IComparer<MyClass> implementation.
I'm not sure that accepting an IComparer<T> really has any major advantages, except for compatibility with legacy code (including .NET Framework classes). The Comparer<T>.Default property is only really useful for primitive types; everything else usually requires extra work to code against.
To avoid code duplication when I need to work with IComparer<T>, one thing I usually do is create a generic comparer, like this:
public class AnonymousComparer<T> : IComparer<T>
{
private Comparison<T> comparison;
public AnonymousComparer(Comparison<T> comparison)
{
if (comparison == null)
throw new ArgumentNullException("comparison");
this.comparison = comparison;
}
public int Compare(T x, T y)
{
return comparison(x, y);
}
}
This allows writing code such as:
myList.BinarySearch(item,
new AnonymousComparer<MyClass>(x.ID.CompareTo(y.ID)));
It's not exactly pretty, but it saves some time.
Another useful class I have is this one:
public class PropertyComparer<T, TProp> : IComparer<T>
where TProp : IComparable
{
private Func<T, TProp> func;
public PropertyComparer(Func<T, TProp> func)
{
if (func == null)
throw new ArgumentNullException("func");
this.func = func;
}
public int Compare(T x, T y)
{
TProp px = func(x);
TProp py = func(y);
return px.CompareTo(py);
}
}
Which you can write code designed for IComparer<T> as:
myList.BinarySearch(item, new PropertyComparer<MyClass, int>(c => c.ID));
The delegate technique is very short (lambda expressions might be even shorter), so if shorter code is your goal, then this is an advantage.
However, implementing the IComparer (and its generic equivalent) makes your code more testable: you can add some unit testing to your comparing class/method.
Furthermore, you can reuse your comparer implementation when composing two or more comparers and combining them as a new comparer. Code reuse with anonymous delegates is harder to achieve.
So, to sum it up:
Anonymous Delegates: shorter (and perhaps cleaner) code
Explicit Implementation: testability and code reuse.
They really address different needs:
IComparable is useful for objects that are ordered. Real numbers should be comparable, but complex numbers cannot - it is ill-defined.
IComparer allows to define re-usable, well-encapsulated comparers. This is especially useful if the comparison needs to know some additional information. For example, you might want to compare dates and times from different time zones. That can be complicated, and a separate comparer should be used for this purpose.
A comparison method is made for simple comparison operations that are not complicated enough for reusability to be of any concern, e.g. sorting a list of customers by their first name. This is simple operation, hence does not need additional data. Likewise, this is not inherent to the object, because the objects are not naturally ordered in any way.
Lastly, there is IEquatable, which might be important if your Equals method can only decide if two objects are equal or not, but if there is no notion of 'larger' and 'smaller', e.g. complex numbers, or vectors in space.
In your case, advantage of having an IComparer<T> over Comparision<T> delegate, is that you can also use it for the Sort method, so you don't need a Comparison delegate version at all.
Another useful thing you can do is implementing a delegated IComparer<T> implementation like this:
public class DelegatedComparer<T> : IComparer<T>
{
Func<T,T,int> _comparision;
public DelegatedComparer(Func<T,T,int> comparision)
{
_comparision = comparision;
}
public int Compare(T a,T b) { return _comparision(a,b); }
}
list.Sort(new DelegatedComparer<Foo>((foo1,foo2)=>foo1.Bar.CompareTo(foo2.Bar));
and a more advanced version:
public class PropertyDelegatorComparer<TSource,TProjected> : DelegatedComparer<TSource>
{
PropertyDelegatorComparer(Func<TSource,TProjected> projection)
: base((a,b)=>projection(a).CompareTo(projection(b)))
}

Is there a built-in IEqualityComparer that compares objects only using their hash value?

Is there a built-in IEqualityComparer that compares objects by the value returned by their GetHashCode value? It's easy to write, but I'd prefer to use a provided class instead of a custom one.
Current code:
private class HashComparer : IEqualityComparer<TKey>
{
private readonly Func<TKey, int> _Hasher;
public HashComparer (Func<TKey, int> hasher)
{
_Hasher = hasher;
}
public bool Equals (TKey x, TKey y)
{
// null supposed to throw, therefore no check
return _Hasher (x) == _Hasher (y);
}
public int GetHashCode (TKey obj)
{
return _Hasher (obj);
}
}
No, such a thing doesn't exist in the framework as far as I'm aware.
It would be a generally Bad Thing - hash codes don't have to be unique, so it couldn't be used to mimic normal equality, other than for types with 2^32 possible values or fewer, and a hash generation algorithm which gives a unique code for each value.
I'm struggling to think of any sensible use for this - which is why you're unlikely to find it in the framework. Perhaps there's some very specialized situation where you'd find it useful, but that's not enough justification to put it in the main framework.
Out of interest, what are you trying to do with it?

Interface constraint for IComparable

When I want to constraint the type T to be comparable, should I use:
where T : IComparable
or
where T : IComparable<T>
I can't get my head around if #2 makes sense. Anyone can explain what the difference would be?
You may want both constraints, as in:
where T : IComparable, IComparable<T>
This would make your type compatible with more users of the IComparable interfaces. The generic version of IComparable, IComparable<T> will help to avoid boxing when T is a value type and allows for more strongly typed implementations of the interface methods. Supporting both ensures that no matter which interface some other object asks for, your object can comply and therefore inter-operate nicely.
For example, Array.Sort and ArrayList.Sort use IComparable, not IComparable<T>.
The main difference between IComparable and IComparable<> is that the first is pre-generics so allows you to call the compare method with any object, whereas the second enforces that it shares the same type:
IComparable - CompareTo(object other);
IComparable<T> - CompareTo(T other);
I would go with the second option provided that you don't intend to use any old .net 1.0 libraries where the types may not implement the modern, generic solution. You'll gain a performance boost since you'll avoid boxing and the comparisons won't need to check the types match and you'll also get the warm feeling that comes from doing things in the most cutting edge way...
To address Jeff's very good and pertinent point I would argue that it is good practice to place as few constraints on a generic as is required to perform the task. Since you are in complete control of the code inside the generic you know whether you are using any methods that require a basic IComparable type. So, taking his comment into consideration I personally would follow these rules:
If you are not expecting the generic to use any types that only implement IComparable (i.e. legacy 1.0 code) and you are not calling any methods from inside the generic that rely on an IComparable parameter then use the IComparable<> constraint only.
If you are using types that only implement IComparable then use that constraint only
If you are using methods that require an IComparable parameter, but not using types that only implement IComparable then using both constraints as in Jeff's answer will boost performance when you use methods that accept the generic type.
To expand on the third rule - let's assume that the class you are writing is as follows:
public class StrangeExample<T> where ... //to be decided
{
public void SortArray(T[] input)
{
Array.Sort(input);
}
public bool AreEqual(T a, T b)
{
return a.CompareTo(b) == 0;
}
}
And we need to decide what constraints to place on it. The SortArray method calls Array.Sort which requires the array that is passed in to contains objects that implement IComparable. Therefore we must have an IComparable constraint:
public class StrangeExample<T> where T : IComparable
Now the class will compile and work correctly as an array of T is valid for Array.Sort and there is a valid .CompareTo method defined in the interface. However, if you are sure that you will not want to use your class with a type that does not also implement the IComparable<> interface you can extend your constraint to:
public class StrangeExample<T> where T : IComparable, IComparable<T>
This means that when AreEqual is called it will use the faster, generic CompareTo method and you will see a performance benefit at the expense of not being able to use it with old, .NET 1.0 types.
On the other hand if you didn't have the AreEqual method then there is no advantage to the IComparable<> constraint so you may as well drop it - you are only using IComparable implementations anyway.
Those are two different interfaces. Before .NET 2.0 there were no generics, so there was just IComparable. With .NET 2.0 came generics and it became possible to make IComparable<T>. They do exactly the same. Basically IComparable is obsolete, although most libraries out there recognize both.
To make your code really compatible, implement both, but make one call the other, so you don't have to write the same code twice.
The IComparable<T> allows the comparator to be strongly typed.
You can have
public int CompareTo(MyType other)
{
// logic
}
as oppose to
public int CompareTo(object other)
{
if (other is MyType)
// logic
}
Take for instance the next example witch implements both interfaces:
public class MyType : IComparable<MyType>, IComparable
{
public MyType(string name, int id)
{ Name = name; Id = id; }
public string Name { get; set; }
public int Id { get; set; }
public int CompareTo(MyType other)
{
if (null == other)
throw new ArgumentNullException("other");
return (Id - other.Id > 0 ? 1 : 0);
}
public int CompareTo(object other)
{
if (null == other)
throw new ArgumentNullException("other");
if (other is MyType)
return (Id - (other as MyType).Id > 0 ? 1 : 0);
else
throw new InvalidOperationException("Bad type");
}
}
MyType t1 = new MyType("a", 1);
MyType t2 = new MyType("b", 2);
object someObj = new object();
// calls the strongly typed method: CompareTo(MyType other)
t1.CompareTo(t2);
// calls the *weakly* typed method: CompareTo(object other)
t1.CompareTo(someObj);
If MyType was only implemented with IComparable<MyType>, the second compareTo(someObj) is a compile time error. This is one advantage of strongly typed generics.
On the other hand, there are methods in the framework that require the non generic IComparable like Array.Sort. In these cases, you should consider implementing both interfaces like in this example.
I would use the second constraint as that will allow you to reference strongly-typed members of the interface. If you go with your first option then you will have to cast to use the interface type.

Abstract Class - Am I over-thinking this or doing it right?

So I am utilizing CollectionBase as an inherited class for custom collections. I am utilizing CollectionBase through an abstract class so that I don't repeated knowledge (following the DRY principle). The abstract class is defined as a generic class also. Here is how I am implementing my class:
public abstract class GenericCollectionBase<T,C> : CollectionBase
{
//Indexders, virtual methods for Add, Contains, IndexOf, etc
}
I utilize this so I don't have to implement these base methods in 10+ classes.
My question is am I taking this too far when I override the Equals method like this:
public override bool Equals(object obj)
{
if (obj is C)
{
GenericCollectionBase<T, C> collB =
obj as GenericCollectionBase<T, C>;
if (this.Count == collB.Count)
{
for (int i = 0; i < this.Count; ++i)
{
if (!this[i].Equals(collB[i]))
return false;
}
return true;
}
}
return false;
}
Am I trying to accomplish too much with my abstract, or doing this the correct way?
EDIT: This is written for .Net 2.0 and do not have access to 3.5 to utilize things like LINQ
I don't believe you are trying to accomplish too much. If an abstract class was meant to not have any implementation at all, or other methods which define functionality, then they would be interfaces.
The only thing I would change is to use EqualityComparer<T> instead of equals for the comparison of this[i] and collB[i].
Well, first, this is weird :
if (obj is C)
{
GenericCollectionBase<T, C> collB = obj as GenericCollectionBase<T, C>;
I'll assume you meant that :
GenericCollectionBase<T, C> collB = obj as GenericCollectionBase<T, C>;
if (collB != null)
{
...
I think you're over-thinking this, except if you really, really need two different collections with the same content to be considered as equal. I'd put this logic in another method to be called explicitly or in an equality comparer.
Making an extension method against IDictionary would be far more useful. There's also methods like Intersect from LINQ that may be useful.
I don't know if you're trying to accomplish too much, but I think you're trying to accomplish the wrong thing. There are cases where you might want that type of equality for collections, but it should be opt-in and obvious from the name of the type. I've created a ListValue<> with the type of equality you're using, but then it's always been immutable as well.
Also, if you're going to do this type of equality check, an initial test using object.ReferenceEquals can save you from having to iterate over a large collection when your comparing an object to itself.

Categories

Resources