/// <summary> /// Compares the properties of two objects of the same type and returns if all properties are equal. /// </summary> /// <param name="objectA">The first object to compare.</param> /// <param name="objectB">The second object to compre.</param> /// <param name="ignoreList">A list of property names to ignore from the comparison.</param> /// <returns><c>true</c> if all property values are equal, otherwise <c>false</c>.</returns> public static bool AreObjectsEqual(this object objectA, object objectB, params string[] ignoreList) { bool result; try { if (objectA != null && objectB != null) { Type objectType; objectType = objectA.GetType(); if (CanDirectlyCompare(objectType)) { return(objectA.Equals(objectB)); } result = true; // assume by default they are equal foreach (PropertyInfo propertyInfo in objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && !ignoreList.Contains(p.Name))) { object valueA; object valueB; try { valueA = propertyInfo.GetValue(objectA, null); valueB = propertyInfo.GetValue(objectB, null); // if it is a primitive type, value type or implements IComparable, just directly try and compare the value if (CanDirectlyCompare(propertyInfo.PropertyType)) { if (!AreValuesEqual(valueA, valueB)) { Console.WriteLine(LocalizedResources.Instance().MismatchWithPropertyFound, objectType.FullName, propertyInfo.Name); result = false; } } // if it implements IEnumerable, then scan any items else if (typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType)) { IEnumerable <object> collectionItems1; IEnumerable <object> collectionItems2; int collectionItemsCount1; int collectionItemsCount2; // null check if (valueA == null && valueB != null || valueA != null && valueB == null) { Console.WriteLine(LocalizedResources.Instance().MismatchWithPropertyFound, objectType.FullName, propertyInfo.Name); result = false; } else if (valueA != null && valueB != null) { collectionItems1 = ((IEnumerable)valueA).Cast <object>(); collectionItems2 = ((IEnumerable)valueB).Cast <object>(); collectionItemsCount1 = collectionItems1.Count(); collectionItemsCount2 = collectionItems2.Count(); // check the counts to ensure they match if (collectionItemsCount1 != collectionItemsCount2) { Console.WriteLine(LocalizedResources.Instance().CollectionCountsForPropertyDoNotMatch, objectType.FullName, propertyInfo.Name); result = false; } // and if they do, compare each item... this assumes both collections have the same order else { for (int i = 0; i < collectionItemsCount1; i++) { object collectionItem1; object collectionItem2; Type collectionItemType; collectionItem1 = collectionItems1.ElementAt(i); collectionItem2 = collectionItems2.ElementAt(i); collectionItemType = collectionItem1.GetType(); if (CanDirectlyCompare(collectionItemType)) { if (!AreValuesEqual(collectionItem1, collectionItem2)) { Console.WriteLine(LocalizedResources.Instance().ItemInPropertyCollectionDoesNotMatch, i, objectType.FullName, propertyInfo.Name); result = false; } } else if (!AreObjectsEqual(collectionItem1, collectionItem2, ignoreList)) { Console.WriteLine(LocalizedResources.Instance().ItemInPropertyCollectionDoesNotMatch, i, objectType.FullName, propertyInfo.Name); result = false; } } } } } else if (propertyInfo.PropertyType.IsClass || propertyInfo.PropertyType.IsInterface) { if (!AreObjectsEqual(propertyInfo.GetValue(objectA, null), propertyInfo.GetValue(objectB, null), ignoreList)) { Console.WriteLine(LocalizedResources.Instance().MismatchWithPropertyFound, objectType.FullName, propertyInfo.Name); result = false; } } else { Console.WriteLine(LocalizedResources.Instance().CannotCompareProperty, objectType.FullName, propertyInfo.Name); result = false; } } catch (System.Reflection.TargetParameterCountException te) { continue; } catch (Exception ex) { Console.WriteLine(LocalizedResources.Instance().CannotCompareValues, ex.Message); result = false; } } } else { result = object.Equals(objectA, objectB); } } catch (System.Exception ex) { Console.WriteLine(LocalizedResources.Instance().CannotCompareValues, ex.Message); result = false; } return(result); }