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(); } } }