From bec731161a49c6368e306162cc736eaa33efc89c Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Sun, 10 Feb 2019 23:02:33 +0300 Subject: [PATCH] Resolved #787: Replace ValueObject implementation --- .../Volo/Abp/Domain/Values/ValueObject.cs | 101 ++++++------------ 1 file changed, 32 insertions(+), 69 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Values/ValueObject.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Values/ValueObject.cs index dccd1c0206..ea84b41792 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Values/ValueObject.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Values/ValueObject.cs @@ -1,98 +1,61 @@ -using System; +using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace Volo.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 + //Inspired from https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/implement-value-objects + + public abstract class ValueObject { - public bool Equals(TValueObject other) + protected static bool EqualOperator(ValueObject left, ValueObject right) { - if ((object)other == null) + if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null)) { return false; } + return ReferenceEquals(left, null) || left.Equals(right); + } - var publicProperties = GetType().GetTypeInfo().GetProperties(); - if (!publicProperties.Any()) - { - return true; - } - - return publicProperties.All(property => Equals(property.GetValue(this, null), property.GetValue(other, null))); + protected static bool NotEqualOperator(ValueObject left, ValueObject right) + { + return !(EqualOperator(left, right)); } + protected abstract IEnumerable GetAtomicValues(); + public override bool Equals(object obj) { - if (obj == null) + if (obj == null || obj.GetType() != GetType()) { return false; } - var item = obj as ValueObject; - return (object)item != null && Equals((TValueObject)item); - } - - public override int GetHashCode() - { - //TODO: Can we cache the hash value assuming value objects are always immutable? We can make a Reset-like method to reset it's mutated. - - const int index = 1; - const int initialHasCode = 31; - - var publicProperties = GetType().GetTypeInfo().GetProperties(); - - if (!publicProperties.Any()) + ValueObject other = (ValueObject)obj; + IEnumerator thisValues = GetAtomicValues().GetEnumerator(); + IEnumerator otherValues = other.GetAtomicValues().GetEnumerator(); + while (thisValues.MoveNext() && otherValues.MoveNext()) { - return initialHasCode; - } - - var hashCode = initialHasCode; - var changeMultiplier = false; - - foreach (var property in publicProperties) - { - var value = property.GetValue(this, null); - - if (value == null) + if (ReferenceEquals(thisValues.Current, null) ^ + ReferenceEquals(otherValues.Current, null)) { - //support {"a",null,null,"a"} != {null,"a","a",null} - hashCode = hashCode ^ (index * 13); - continue; + return false; } - 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; + if (thisValues.Current != null && + !thisValues.Current.Equals(otherValues.Current)) + { + return false; + } } - - return x.Equals(y); + return !thisValues.MoveNext() && !otherValues.MoveNext(); } - public static bool operator !=(ValueObject x, ValueObject y) + public override int GetHashCode() { - return !(x == y); + return GetAtomicValues() + .Select(x => x != null ? x.GetHashCode() : 0) + .Aggregate((x, y) => x ^ y); } + // Other utilility methods } }