mirror of https://github.com/abpframework/abp.git
1 changed files with 32 additions and 69 deletions
@ -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/
|
|||
|
|||
/// <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> |
|||
//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<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()) |
|||
ValueObject other = (ValueObject)obj; |
|||
IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator(); |
|||
IEnumerator<object> 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<TValueObject> x, ValueObject<TValueObject> 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<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…
Reference in new issue