public static bool ListsEqual <T>(IList <T> v1,
                                   IList <T> v2)
 {
     if (v1.Count != v2.Count)
     {
         return(false);
     }
     for (int i = 0; i < v1.Count; i++)
     {
         if (!CollectionUtil.Equals(v1[i], v2[i]))
         {
             return(false);
         }
     }
     return(true);
 }
 public static bool DictionariesEqual <K, V>(IDictionary <K, V> m1,
                                             IDictionary <K, V> m2)
 {
     if (m1.Count != m2.Count)
     {
         return(false);
     }
     foreach (KeyValuePair <K, V> entry1 in m1)
     {
         K key1 = entry1.Key;
         V val1 = entry1.Value;
         if (!m2.ContainsKey(key1))
         {
             return(false);
         }
         Object val2 = m2[key1];
         if (!CollectionUtil.Equals(val1, val2))
         {
             return(false);
         }
     }
     return(true);
 }
        /// <summary>
        /// Equality function that properly handles arrays,
        /// lists, maps, lists of arrays, and maps of arrays.
        /// </summary>
        /// <remarks>
        /// <para>
        /// NOTE: For Sets, this relies on the equals method
        /// of the Set to do the right thing. This is a reasonable
        /// assumption since, in order for Sets to behave
        /// properly as Sets, their values must already have
        /// a proper implementation of equals. (Or they must
        /// be specialized Sets that define a custom comparator that
        /// knows how to do the right thing). The same holds true for Map keys.
        /// Map values, on the other hand, are compared (so Map values
        /// can be arrays).
        /// </para>
        /// </remarks>
        /// <param name="o1">The first object. May be null.</param>
        /// <param name="o2">The second object. May be null.</param>
        /// <returns>true iff the two objects are equal.</returns>
        public new static bool Equals(Object o1, Object o2)
        {
            if (o1 == o2)
            { //same object or both null
                return(true);
            }
            else if (o1 == null)
            {
                return(false);
            }
            else if (o2 == null)
            {
                return(false);
            }
            else if (o1 is Array)
            {
                Type clazz1 = o1.GetType();
                Type clazz2 = o2.GetType();
                if (!clazz1.Equals(clazz2))
                {
                    return(false);
                }
                Array array1  = (Array)o1;
                Array array2  = (Array)o2;
                int   length1 = array1.Length;
                int   length2 = array2.Length;
                if (length1 != length2)
                {
                    return(false);
                }
                for (int i = 0; i < length1; i++)
                {
                    Object el1 = array1.GetValue(i);
                    Object el2 = array2.GetValue(i);
                    if (!CollectionUtil.Equals(el1, el2))
                    {
                        return(false);
                    }
                }
                return(true);
            }
            else if (ReflectionUtil.IsParentTypeOf(typeof(IList <>), o1.GetType()))
            {
                Type parent1 = ReflectionUtil.FindInHierarchyOf(typeof(IList <>), o1.GetType());
                Type parent2 = ReflectionUtil.FindInHierarchyOf(typeof(IList <>), o2.GetType());
                if (!parent1.Equals(parent2))
                {
                    return(false);
                }
                Type[] genericArguments =
                    parent1.GetGenericArguments();


                Type       collectionUtil = typeof(CollectionUtil);
                MethodInfo info           = collectionUtil.GetMethod("ListsEqual");

                info = info.MakeGenericMethod(genericArguments);

                Object rv = info.Invoke(null, new object[] { o1, o2 });
                return((bool)rv);
            }
            else if (ReflectionUtil.IsParentTypeOf(typeof(IDictionary <,>), o1.GetType()))
            {
                Type parent1 = ReflectionUtil.FindInHierarchyOf(typeof(IDictionary <,>), o1.GetType());
                Type parent2 = ReflectionUtil.FindInHierarchyOf(typeof(IDictionary <,>), o2.GetType());
                if (!parent1.Equals(parent2))
                {
                    return(false);
                }
                Type[] genericArguments =
                    parent1.GetGenericArguments();


                Type       collectionUtil = typeof(CollectionUtil);
                MethodInfo info           = collectionUtil.GetMethod("DictionariesEqual");

                info = info.MakeGenericMethod(genericArguments);

                Object rv = info.Invoke(null, new object[] { o1, o2 });
                return((bool)rv);
            }
            else if (ReflectionUtil.IsParentTypeOf(typeof(ICollection <>), o1.GetType()))
            {
                Type parent1 = ReflectionUtil.FindInHierarchyOf(typeof(ICollection <>), o1.GetType());
                Type parent2 = ReflectionUtil.FindInHierarchyOf(typeof(ICollection <>), o2.GetType());
                if (!parent1.Equals(parent2))
                {
                    return(false);
                }
                Type[] genericArguments =
                    parent1.GetGenericArguments();


                Type       collectionUtil = typeof(CollectionUtil);
                MethodInfo info           = collectionUtil.GetMethod("SetsEqual");

                info = info.MakeGenericMethod(genericArguments);

                Object rv = info.Invoke(null, new object[] { o1, o2 });
                return((bool)rv);
            }
            else
            {
                return(o1.Equals(o2));
            }
        }