Much to my surprise I found that .NET 3.5 doesn’t seem to have a native method for comparing two arrays or collections of any type.  The LINQ extension methods offer a whole lot of added functionality for IEnumerable<T> collections, but not native comparison.  The Equals method is still the base object.Equals method that does a reference equality (i.e. Are these two the same object?) not a value equality (do they contain the same values?)

So, finding myself needing an equality comparison between two arrays, I’ve written the following extension method:

   1: /// <summary>
   2: /// Checks whether a collection is the same as another collection
   3: /// </summary>
   4: /// <param name=”value”>The current instance object</param>
   5: /// <param name=”compareList”>The collection to compare with</param>
   6: /// <param name=”comparer”>The comparer object to use to compare each item in the collection.  If null uses EqualityComparer(T).Default</param>
   7: /// <returns>True if the two collections contain all the same items in the same order</returns>
   8: public static bool IsEqualTo<TSource>(this IEnumerable<TSource> value, IEnumerable<TSource> compareList, IEqualityComparer<TSource> comparer)
   9: {
  10:     if (value == compareList)
  11:     {
  12:         return true;
  13:     }
  14:     else if (value == null || compareList == null)
  15:     {
  16:         return false;
  17:     }
  18:     else
  19:     {
  20:         if (comparer == null)
  21:         {
  22:             comparer = EqualityComparer<TSource>.Default;
  23:         }
  24:  
  25:         IEnumerator<TSource> enumerator1 = value.GetEnumerator();
  26:         IEnumerator<TSource> enumerator2 = compareList.GetEnumerator();
  27:  
  28:         bool enum1HasValue = enumerator1.MoveNext();
  29:         bool enum2HasValue = enumerator2.MoveNext();
  30:  
  31:         try
  32:         {
  33:             while (enum1HasValue && enum2HasValue)
  34:             {
  35:                 if (!comparer.Equals(enumerator1.Current, enumerator2.Current))
  36:                 {
  37:                     return false;
  38:                 }
  39:  
  40:                 enum1HasValue = enumerator1.MoveNext();
  41:                 enum2HasValue = enumerator2.MoveNext();
  42:             }
  43:  
  44:             return !(enum1HasValue || enum2HasValue);
  45:         }
  46:         finally
  47:         {
  48:             if (enumerator1 != null) enumerator1.Dispose();
  49:             if (enumerator2 != null) enumerator2.Dispose();
  50:         }
  51:     }
  52: }
  53:  
  54: public static bool IsEqualTo<TSource>(this IEnumerable<TSource> value, IEnumerable<TSource> compareList)
  55: {
  56:     return IsEqualTo(value, compareList, null);
  57: }
  58:  
  59: public static bool IsEqualTo(this IEnumerable value, IEnumerable compareList)
  60: {
  61:     return IsEqualTo<object>(value.OfType<object>(), compareList.OfType<object>());
  62: }

Updated: Jugen (see comment below) made some quality suggestions that I’ve used to improve the code here.  To see the state of the code when the comment was made, see here.

It gives you an extension methods on any collection that implements IEnumerable<T>.  There is an optional parameter of type IEqualityComparer<TSource> which if not null will be used to compare each item in the collections.  Otherwise it will use the default comparer for TSource. It will also work for untyped IEnumerable collections, the overloaded method passes the collections through to the IsEqualTo<TSource> method with object as the TSource.  This is really just there for backwards compatibility.

As far as speed goes, I ran a test with 2 collections of 10,000,000 (I stopped there because I started getting out of memory exceptions when I was populating the test collections after that!) items & it took 0.89 seconds, so I think that’d do for most scenarios.  If you want to use this code you can grab a copy of it here.

[?]