-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathEntity[TId].cs
100 lines (91 loc) · 3.88 KB
/
Entity[TId].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
using System;
#if NET40
#else
using System.Reflection;
#endif
namespace CoreDdd.Domain
{
/// <summary>
/// Base class for domain entities with an id of a different type than int.
/// Derive from <see cref="Entity"/> if you need an entity with an id of type int.
/// </summary>
public abstract class Entity<TId>
{
/// <summary>
/// Entity id.
/// </summary>
public virtual TId Id { get; protected set; }
/// <summary>
/// Determines whether two entity instances are equal.
/// </summary>
/// <param name="otherObject">the object to compare with the current entity</param>
/// <returns>true if the other object is an entity of the same type with the same id, otherwise returns false</returns>
public override bool Equals(object otherObject)
{
var other = otherObject as Entity<TId>;
if (ReferenceEquals(other, null)) return false;
if (ReferenceEquals(other, this)) return true;
if (!_isTransient(other) && !_isTransient(this) && Id.Equals(other.Id))
{
var otherType = other.GetUnproxiedType();
var thisType = GetUnproxiedType();
#if NET40
return thisType.IsAssignableFrom(otherType)
|| otherType.IsAssignableFrom(thisType);
#else
return thisType.GetTypeInfo().IsAssignableFrom(otherType.GetTypeInfo())
|| otherType.GetTypeInfo().IsAssignableFrom(thisType.GetTypeInfo());
#endif
}
return false;
bool _isTransient(Entity<TId> entity)
{
return Equals(entity.Id, default(TId));
}
}
/// <summary>
/// Don't touch or override this method. Needs to stay as it is to be able to compare an entity with it's parent entity proxy.
/// see test when_comparing_derived_entity_with_parent_entity_proxy testing this scenario
/// </summary>
/// <returns>An unproxied type</returns>
protected virtual Type GetUnproxiedType()
{
return GetType();
}
private int? _originalHashCode;
/// <summary>
/// Overrides the hash code.
/// </summary>
/// <returns>The default hash code for transient (Id == default(TId)) entities, and Id.GetHashCode() for non-transient entities</returns>
public override int GetHashCode()
{
if (!_originalHashCode.HasValue)
{
_originalHashCode = Equals(Id, default(TId))
? base.GetHashCode()
: Id.GetHashCode();
}
return _originalHashCode.Value; // hashset/dictionary requires that GetHashCode() returns the same value for the lifetime of the object
}
/// <summary>
/// Entity equality == operator compares entities via overridden <see cref="Equals"/> method.
/// </summary>
/// <param name="entityOne">Entity one to compare</param>
/// <param name="entityTwo">Entity two to compare</param>
/// <returns>True if entities are equal</returns>
public static bool operator ==(Entity<TId> entityOne, Entity<TId> entityTwo)
{
return Equals(entityOne, entityTwo);
}
/// <summary>
/// Entity inequality == operator compares entities via overridden <see cref="Equals"/> method.
/// </summary>
/// <param name="entityOne">Entity one to compare</param>
/// <param name="entityTwo">Entity two to compare</param>
/// <returns>True if entities are not equal</returns>
public static bool operator !=(Entity<TId> entityOne, Entity<TId> entityTwo)
{
return !Equals(entityOne, entityTwo);
}
}
}