using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace AioNet.Reflection { public static class DeepComparison { public static bool RecursiveFieldsEqual(this T first, T second) { Type type = typeof(T); return first.RecursiveFieldsEqual(second, type); } public static bool RecursiveFieldsEqual(this object first, object second, Type type) { // If both are null, return true. if (first is null && second is null) { return true; } // If one of them is null and the other one isn't, return false. if (first is null || second is null) { return false; } // If type is value type or a String, simply return result of Equals. if (type.IsValueType || type.Equals(typeof(string))) { return first.Equals(second); } // If type is IEnumerable, compare individual elements. if (type.GetInterface("System.Collections.IEnumerable") != null) { return RecursiveEnumerableEquals(first, second); } IEnumerable fields = type.GetRuntimeFields(); return fields.All(field => { return RecursiveFieldsEqual( field.GetValue(first), field.GetValue(second), field.FieldType ); }); } private static bool RecursiveEnumerableEquals(T first, T second) { // Throwing exceptions if casting to System.Collections.IEnumerable doesn't work. IEnumerator firstEnumerator = ((IEnumerable)first).GetEnumerator(); IEnumerator secondEnumerator = ((IEnumerable)second).GetEnumerator(); while (firstEnumerator.MoveNext()) { // If the second enumerator doesn't advance when first does, // this means that first enumerator has more elements, so they // can't be equal. if (!secondEnumerator.MoveNext()) { return false; } Type firstType = firstEnumerator.Current.GetType(); Type secondType = secondEnumerator.Current.GetType(); // If types don't match, they can't be equal. if (!(firstType == secondType)) { return false; } bool elementsEqual = RecursiveFieldsEqual( firstEnumerator.Current, secondEnumerator.Current, firstType ); // If the two elements are not equal, then the entire enumerable is not equal. if (!elementsEqual) { return false; } } // If second enumerator can move even though first can't, it's // longer and therefore the two are not equal. if (secondEnumerator.MoveNext()) { return false; } // If there were no differences found, we return true. return true; } } }