-
Notifications
You must be signed in to change notification settings - Fork 320
/
Copy pathValueObject.cs
122 lines (94 loc) · 2.98 KB
/
ValueObject.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System;
using System.Collections.Generic;
using System.Linq;
namespace PluralsightDdd.SharedKernel
{
/// <summary>
/// See: https://enterprisecraftsmanship.com/posts/value-object-better-implementation/
/// </summary>
[Serializable]
public abstract class ValueObject : IComparable, IComparable<ValueObject>
{
private int? _cachedHashCode;
protected abstract IEnumerable<object> GetEqualityComponents();
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (GetUnproxiedType(this) != GetUnproxiedType(obj))
return false;
var valueObject = (ValueObject)obj;
return GetEqualityComponents().SequenceEqual(valueObject.GetEqualityComponents());
}
public override int GetHashCode()
{
if (!_cachedHashCode.HasValue)
{
_cachedHashCode = GetEqualityComponents()
.Aggregate(1, (current, obj) =>
{
unchecked
{
return current * 23 + (obj?.GetHashCode() ?? 0);
}
});
}
return _cachedHashCode.Value;
}
public int CompareTo(object obj)
{
Type thisType = GetUnproxiedType(this);
Type otherType = GetUnproxiedType(obj);
if (thisType != otherType)
return string.Compare(thisType.ToString(), otherType.ToString(), StringComparison.Ordinal);
var other = (ValueObject)obj;
object[] components = GetEqualityComponents().ToArray();
object[] otherComponents = other.GetEqualityComponents().ToArray();
for (int i = 0; i < components.Length; i++)
{
int comparison = CompareComponents(components[i], otherComponents[i]);
if (comparison != 0)
return comparison;
}
return 0;
}
private int CompareComponents(object object1, object object2)
{
if (object1 is null && object2 is null)
return 0;
if (object1 is null)
return -1;
if (object2 is null)
return 1;
if (object1 is IComparable comparable1 && object2 is IComparable comparable2)
return comparable1.CompareTo(comparable2);
return object1.Equals(object2) ? 0 : -1;
}
public int CompareTo(ValueObject other)
{
return CompareTo(other as object);
}
public static bool operator ==(ValueObject a, ValueObject b)
{
if (a is null && b is null)
return true;
if (a is null || b is null)
return false;
return a.Equals(b);
}
public static bool operator !=(ValueObject a, ValueObject b)
{
return !(a == b);
}
internal static Type GetUnproxiedType(object obj)
{
const string EFCoreProxyPrefix = "Castle.Proxies.";
const string NHibernateProxyPostfix = "Proxy";
Type type = obj.GetType();
string typeString = type.ToString();
if (typeString.Contains(EFCoreProxyPrefix) || typeString.EndsWith(NHibernateProxyPostfix))
return type.BaseType;
return type;
}
}
}