Resolved #787: Replace ValueObject implementation

pull/847/head
Halil ibrahim Kalkan 6 years ago
parent fbaac6ef76
commit bec731161a

@ -1,98 +1,61 @@
using System; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
namespace Volo.Abp.Domain.Values 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/ //Inspired from https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/implement-value-objects
/// <summary> public abstract class ValueObject
/// Base class for value objects.
/// </summary>
/// <typeparam name="TValueObject">The type of the value object.</typeparam>
public abstract class ValueObject<TValueObject> : IEquatable<TValueObject>
where TValueObject : ValueObject<TValueObject>
{ {
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 false;
} }
return ReferenceEquals(left, null) || left.Equals(right);
}
var publicProperties = GetType().GetTypeInfo().GetProperties(); protected static bool NotEqualOperator(ValueObject left, ValueObject right)
if (!publicProperties.Any()) {
{ return !(EqualOperator(left, right));
return true;
}
return publicProperties.All(property => Equals(property.GetValue(this, null), property.GetValue(other, null)));
} }
protected abstract IEnumerable<object> GetAtomicValues();
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj == null) if (obj == null || obj.GetType() != GetType())
{ {
return false; return false;
} }
var item = obj as ValueObject<TValueObject>; ValueObject other = (ValueObject)obj;
return (object)item != null && Equals((TValueObject)item); IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator();
} IEnumerator<object> otherValues = other.GetAtomicValues().GetEnumerator();
while (thisValues.MoveNext() && otherValues.MoveNext())
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())
{ {
return initialHasCode; if (ReferenceEquals(thisValues.Current, null) ^
} ReferenceEquals(otherValues.Current, null))
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} return false;
hashCode = hashCode ^ (index * 13);
continue;
} }
hashCode = hashCode * (changeMultiplier ? 59 : 114) + value.GetHashCode(); if (thisValues.Current != null &&
changeMultiplier = !changeMultiplier; !thisValues.Current.Equals(otherValues.Current))
} {
return false;
return hashCode; }
}
public static bool operator ==(ValueObject<TValueObject> x, ValueObject<TValueObject> y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (((object)x == null) || ((object)y == null))
{
return false;
} }
return !thisValues.MoveNext() && !otherValues.MoveNext();
return x.Equals(y);
} }
public static bool operator !=(ValueObject<TValueObject> x, ValueObject<TValueObject> 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
} }
} }

Loading…
Cancel
Save