using Abp.Reflection;
using System;
using System.Linq;
using System.Reflection;
namespace Abp.Domain.Values
{
//Inspired from https://blogs.msdn.microsoft.com/cesardelatorre/2011/06/06/implementing-a-value-object-base-class-supertype-patternddd-patterns-related/
///
/// Base class for value objects.
///
/// The type of the value object.
public abstract class ValueObject : IEquatable
where TValueObject : ValueObject
{
public bool Equals(TValueObject other)
{
if ((object)other == null)
{
return false;
}
var publicProperties = GetPropertiesForCompare();
if (!publicProperties.Any())
{
return true;
}
return publicProperties.All(property => Equals(property.GetValue(this, null), property.GetValue(other, null)));
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
var item = obj as ValueObject;
return (object)item != null && Equals((TValueObject)item);
}
public override int GetHashCode()
{
const int index = 1;
const int initialHasCode = 31;
var publicProperties = GetPropertiesForCompare();
if (!publicProperties.Any())
{
return initialHasCode;
}
var hashCode = initialHasCode;
var changeMultiplier = false;
foreach (var property in publicProperties)
{
var value = property.GetValue(this, null);
if (value == null)
{
//support {"a",null,null,"a"} != {null,"a","a",null}
hashCode = hashCode ^ (index * 13);
continue;
}
hashCode = hashCode * (changeMultiplier ? 59 : 114) + value.GetHashCode();
changeMultiplier = !changeMultiplier;
}
return hashCode;
}
public static bool operator ==(ValueObject x, ValueObject y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (((object)x == null) || ((object)y == null))
{
return false;
}
return x.Equals(y);
}
public static bool operator !=(ValueObject x, ValueObject y)
{
return !(x == y);
}
private PropertyInfo[] GetPropertiesForCompare()
{
return GetType().GetTypeInfo().GetProperties().Where(t => ReflectionHelper.GetSingleAttributeOrDefault(t) == null).ToArray();
}
}
}