183 lines
6.7 KiB
C#
183 lines
6.7 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace Unosquare.Swan.Components {
|
|
/// <summary>
|
|
/// Represents a quick object comparer using the public properties of an object
|
|
/// or the public members in a structure.
|
|
/// </summary>
|
|
public static class ObjectComparer {
|
|
/// <summary>
|
|
/// Compare if two variables of the same type are equal.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of objects to compare.</typeparam>
|
|
/// <param name="left">The left.</param>
|
|
/// <param name="right">The right.</param>
|
|
/// <returns><c>true</c> if the variables are equal; otherwise, <c>false</c>.</returns>
|
|
public static Boolean AreEqual<T>(T left, T right) => AreEqual(left, right, typeof(T));
|
|
|
|
/// <summary>
|
|
/// Compare if two variables of the same type are equal.
|
|
/// </summary>
|
|
/// <param name="left">The left.</param>
|
|
/// <param name="right">The right.</param>
|
|
/// <param name="targetType">Type of the target.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the variables are equal; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
/// <exception cref="ArgumentNullException">targetType.</exception>
|
|
public static Boolean AreEqual(Object left, Object right, Type targetType) {
|
|
if(targetType == null) {
|
|
throw new ArgumentNullException(nameof(targetType));
|
|
}
|
|
|
|
return Definitions.BasicTypesInfo.ContainsKey(targetType)
|
|
? Equals(left, right)
|
|
: targetType.IsValueType() || targetType.IsArray
|
|
? AreStructsEqual(left, right, targetType)
|
|
: AreObjectsEqual(left, right, targetType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare if two objects of the same type are equal.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of objects to compare.</typeparam>
|
|
/// <param name="left">The left.</param>
|
|
/// <param name="right">The right.</param>
|
|
/// <returns><c>true</c> if the objects are equal; otherwise, <c>false</c>.</returns>
|
|
public static Boolean AreObjectsEqual<T>(T left, T right)
|
|
where T : class => AreObjectsEqual(left, right, typeof(T));
|
|
|
|
/// <summary>
|
|
/// Compare if two objects of the same type are equal.
|
|
/// </summary>
|
|
/// <param name="left">The left.</param>
|
|
/// <param name="right">The right.</param>
|
|
/// <param name="targetType">Type of the target.</param>
|
|
/// <returns><c>true</c> if the objects are equal; otherwise, <c>false</c>.</returns>
|
|
/// <exception cref="ArgumentNullException">targetType.</exception>
|
|
public static Boolean AreObjectsEqual(Object left, Object right, Type targetType) {
|
|
if(targetType == null) {
|
|
throw new ArgumentNullException(nameof(targetType));
|
|
}
|
|
|
|
PropertyInfo[] properties = Runtime.PropertyTypeCache.RetrieveAllProperties(targetType).ToArray();
|
|
|
|
foreach(PropertyInfo propertyTarget in properties) {
|
|
Func<Object, Object> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare if two structures of the same type are equal.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of structs to compare.</typeparam>
|
|
/// <param name="left">The left.</param>
|
|
/// <param name="right">The right.</param>
|
|
/// <returns><c>true</c> if the structs are equal; otherwise, <c>false</c>.</returns>
|
|
public static Boolean AreStructsEqual<T>(T left, T right)
|
|
where T : struct => AreStructsEqual(left, right, typeof(T));
|
|
|
|
/// <summary>
|
|
/// Compare if two structures of the same type are equal.
|
|
/// </summary>
|
|
/// <param name="left">The left.</param>
|
|
/// <param name="right">The right.</param>
|
|
/// <param name="targetType">Type of the target.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the structs are equal; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
/// <exception cref="ArgumentNullException">targetType.</exception>
|
|
public static Boolean AreStructsEqual(Object left, Object right, Type targetType) {
|
|
if(targetType == null) {
|
|
throw new ArgumentNullException(nameof(targetType));
|
|
}
|
|
|
|
IEnumerable<MemberInfo> fields = new List<MemberInfo>(Runtime.FieldTypeCache.RetrieveAllFields(targetType))
|
|
.Union(Runtime.PropertyTypeCache.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<Object, Object> targetPropertyGetMethod = property.GetCacheGetMethod();
|
|
|
|
if(targetPropertyGetMethod != null &&
|
|
!Equals(targetPropertyGetMethod(left), targetPropertyGetMethod(right))) {
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare if two enumerables are equal.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of enums to compare.</typeparam>
|
|
/// <param name="left">The left.</param>
|
|
/// <param name="right">The right.</param>
|
|
/// <returns>
|
|
/// True if two specified types are equal; otherwise, false.
|
|
/// </returns>
|
|
/// <exception cref="ArgumentNullException">
|
|
/// left
|
|
/// or
|
|
/// right.
|
|
/// </exception>
|
|
public static Boolean AreEnumerationsEquals<T>(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<Object>().ToArray();
|
|
Object[] rightEnumerable = right.Cast<Object>().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;
|
|
}
|
|
}
|
|
} |