using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using Swan.Reflection; namespace Swan { /// /// Represents a quick object comparer using the public properties of an object /// or the public members in a structure. /// public static class ObjectComparer { /// /// Compare if two variables of the same type are equal. /// /// The type of objects to compare. /// The left. /// The right. /// true if the variables are equal; otherwise, false. public static bool AreEqual(T left, T right) => AreEqual(left, right, typeof(T)); /// /// Compare if two variables of the same type are equal. /// /// The left. /// The right. /// Type of the target. /// /// true if the variables are equal; otherwise, false. /// /// targetType. public static bool AreEqual(object left, object right, Type targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); if (Definitions.BasicTypesInfo.Value.ContainsKey(targetType)) return Equals(left, right); return targetType.IsValueType || targetType.IsArray ? AreStructsEqual(left, right, targetType) : AreObjectsEqual(left, right, targetType); } /// /// Compare if two objects of the same type are equal. /// /// The type of objects to compare. /// The left. /// The right. /// true if the objects are equal; otherwise, false. public static bool AreObjectsEqual(T left, T right) where T : class { return AreObjectsEqual(left, right, typeof(T)); } /// /// Compare if two objects of the same type are equal. /// /// The left. /// The right. /// Type of the target. /// true if the objects are equal; otherwise, false. /// targetType. public static bool AreObjectsEqual(object left, object right, Type targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); var properties = PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(targetType).ToArray(); foreach (var propertyTarget in properties) { var targetPropertyGetMethod = propertyTarget.GetCacheGetMethod(); if (propertyTarget.PropertyType.IsArray) { var leftObj = targetPropertyGetMethod(left) as IEnumerable; var rightObj = targetPropertyGetMethod(right) as IEnumerable; if (!AreEnumerationsEquals(leftObj, rightObj)) return false; } else { if (!Equals(targetPropertyGetMethod(left), targetPropertyGetMethod(right))) return false; } } return true; } /// /// Compare if two structures of the same type are equal. /// /// The type of structs to compare. /// The left. /// The right. /// true if the structs are equal; otherwise, false. public static bool AreStructsEqual(T left, T right) where T : struct { return AreStructsEqual(left, right, typeof(T)); } /// /// Compare if two structures of the same type are equal. /// /// The left. /// The right. /// Type of the target. /// /// true if the structs are equal; otherwise, false. /// /// targetType. public static bool AreStructsEqual(object left, object right, Type targetType) { if (targetType == null) throw new ArgumentNullException(nameof(targetType)); var fields = new List(FieldTypeCache.DefaultCache.Value.RetrieveAllFields(targetType)) .Union(PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(targetType)); foreach (var targetMember in fields) { switch (targetMember) { case FieldInfo field: if (Equals(field.GetValue(left), field.GetValue(right)) == false) return false; break; case PropertyInfo property: var targetPropertyGetMethod = property.GetCacheGetMethod(); if (targetPropertyGetMethod != null && !Equals(targetPropertyGetMethod(left), targetPropertyGetMethod(right))) return false; break; } } return true; } /// /// Compare if two enumerables are equal. /// /// The type of enums to compare. /// The left. /// The right. /// /// true if two specified types are equal; otherwise, false. /// /// /// left /// or /// right. /// public static bool AreEnumerationsEquals(T left, T right) where T : IEnumerable { if (Equals(left, default(T))) throw new ArgumentNullException(nameof(left)); if (Equals(right, default(T))) throw new ArgumentNullException(nameof(right)); var leftEnumerable = left.Cast().ToArray(); var rightEnumerable = right.Cast().ToArray(); if (leftEnumerable.Length != rightEnumerable.Length) return false; for (var i = 0; i < leftEnumerable.Length; i++) { var leftEl = leftEnumerable[i]; var rightEl = rightEnumerable[i]; if (!AreEqual(leftEl, rightEl, leftEl.GetType())) { return false; } } return true; } } }