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.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/
//Inspired from https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/implement-value-objects
/// <summary>
/// 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 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())
protected static bool NotEqualOperator(ValueObject left, ValueObject right)
{
return true;
return !(EqualOperator(left, right));
}
return publicProperties.All(property => Equals(property.GetValue(this, null), property.GetValue(other, null)));
}
protected abstract IEnumerable<object> GetAtomicValues();
public override bool Equals(object obj)
{
if (obj == null)
if (obj == null || obj.GetType() != GetType())
{
return false;
}
var item = obj as ValueObject<TValueObject>;
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())
{
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<TValueObject> x, ValueObject<TValueObject> y)
ValueObject other = (ValueObject)obj;
IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator();
IEnumerator<object> otherValues = other.GetAtomicValues().GetEnumerator();
while (thisValues.MoveNext() && otherValues.MoveNext())
{
if (ReferenceEquals(x, y))
if (ReferenceEquals(thisValues.Current, null) ^
ReferenceEquals(otherValues.Current, null))
{
return true;
return false;
}
if (((object)x == null) || ((object)y == null))
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<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