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.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…
Reference in new issue