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