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 Boolean 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 Boolean 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 Boolean AreObjectsEqual(T left, T right) where T : class => 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 Boolean AreObjectsEqual(Object left, Object right, Type targetType) { if(targetType == null) { throw new ArgumentNullException(nameof(targetType)); } PropertyInfo[] properties = PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(targetType).ToArray(); foreach(PropertyInfo propertyTarget in properties) { Func targetPropertyGetMethod = propertyTarget.GetCacheGetMethod(); if(propertyTarget.PropertyType.IsArray) { IEnumerable leftObj = targetPropertyGetMethod(left) as IEnumerable; IEnumerable 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 Boolean AreStructsEqual(T left, T right) where T : struct => 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 Boolean AreStructsEqual(Object left, Object right, Type targetType) { if(targetType == null) { throw new ArgumentNullException(nameof(targetType)); } IEnumerable fields = new List(FieldTypeCache.DefaultCache.Value.RetrieveAllFields(targetType)).Union(PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(targetType)); foreach(MemberInfo targetMember in fields) { switch(targetMember) { case FieldInfo field: if(Equals(field.GetValue(left), field.GetValue(right)) == false) { return false; } break; case PropertyInfo property: Func 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 Boolean 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)); } Object[] leftEnumerable = left.Cast().ToArray(); Object[] rightEnumerable = right.Cast().ToArray(); if(leftEnumerable.Length != rightEnumerable.Length) { return false; } for(Int32 i = 0; i < leftEnumerable.Length; i++) { Object leftEl = leftEnumerable[i]; Object rightEl = rightEnumerable[i]; if(!AreEqual(leftEl, rightEl, leftEl.GetType())) { return false; } } return true; } } }