DDD Entity - are two entities with default identity considered equal - c#

I want to apply/practice DDD with my new project hence I am creating those typical DDD base classes, i.e., Entity, ValueObject, AggregateRoot and so on.
Question:
When you have the Entity base object implement IEquatable, should two entities with default value of the identity (Id) be considered as Not equal or equal?
For example, I use Guid type for the identity
public interface IEntity
{
Guid LocalId { get; }
}
public abstract class Entity : IEntity, IEquatable<Entity>
{
public Guid LocalId { get; private set; }
protected Entity()
{
this.LocalId = Guid.Empty;
}
protected Entity(Guid id)
{
if (Guid.Empty == id)
{
id = Guid.NewGuid();
}
this.LocalId = id;
}
public bool Equals(Entity other)
{
if (ReferenceEquals(other, null))
{
return false;
}
if (ReferenceEquals(other, this))
{
return true;
}
// **Question** - should I return false or true here?
if (other.LocalId == Guid.Empty && this.LocalId == Guid.Empty)
{
return false;
}
return (other.LocalId == this.LocalId);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(obj, null))
{
return false;
}
if (ReferenceEquals(obj, this))
{
return true;
}
if (!obj.GetType().Equals(typeof(Entity)))
{
return false;
}
return Equals((Entity)obj);
}
public override int GetHashCode()
{
return this.LocalId.GetHashCode();
}
public static bool operator==(Entity left, Entity right)
{
return Equals(left, right);
}
public static bool operator!=(Entity left, Entity right)
{
return !Equals(left, right);
}
}

If you want to follow the book on this then remember that:
An object that is not defined by its attributes, but rather by a
thread of continuity and its identity.
Now, in this context identity means "the property of objects that distinguishes them from other objects", which in most cases means the entity primary key (if your entities are persisted in a database) or some kind of Id attribute, in most cases a GUID will do the trick.
So to answer your question:
Yes, they're the same entity.
Be careful with how you create your
Id's

Related

Can record to be replaced with class in C#

I have a code that it was use the record to define a member .But I have another project in lower version of .net core , it seems can not use record . How can I change it with class?
origin :
public record BucketObject(string name, string urn);
can be changed with :
public class BucketObject
{
public BucketObject(string _name, string _urn)
{
_name = name;
_urn = urn;
}
public string name { get; set; }
public string urn { get; set; }
};
First of all, the easiest way would be to add <LangVersion>latest</LangVersion> to your project file and add a IsExternalInit class.
namespace System.Runtime.CompilerServices
{
using System.ComponentModel;
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class IsExternalInit
{
}
}
If that is not an option the corresponding class would be
public class BucketObject : IEquatable<BucketObject>
{
public BucketObject(string name, string urn)
{
Name = name;
Urn = urn;
}
public string Name { get; }
public string Urn { get; }
public bool Equals(BucketObject other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Name == other.Name && Urn == other.Urn;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((BucketObject)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((Name != null ? Name.GetHashCode() : 0) * 397) ^ (Urn != null ? Urn.GetHashCode() : 0);
}
}
public static bool operator ==(BucketObject left, BucketObject right) => Equals(left, right);
public static bool operator !=(BucketObject left, BucketObject right) => !Equals(left, right);
};
You might note that most of the code is in the equality comparison methods, these are one of the things the records get you for free. You might also note that the object is immutable, so you do not have to worry about the object changing, or the difference between class/struct.
You will also be missing out on the myBucket with {Name = "newName"} syntax, and that is just unavoidable as far as I know.
You might also just consider upgrading your projects. Life tend to be easier if you keep all the projects at the same version. And if you are already on .net core, updating should be fairly painless.

Trouble with generics using custom equality comparison [duplicate]

This question already has answers here:
IEquatable, how to implement this properly [duplicate]
(2 answers)
Closed 2 years ago.
I have a class heirarchy as follows:
public abstract class Issue
{
// some base properties
// these are not included in equality checks for deriving classes
// also not performing equality checks on this base class (it is abstract anyway)
}
public class IssueTypeA : Issue, IEquatable<IssueTypeA>
{
// some properties specific to this class
// these are the two for which equality comparison is performed
public string requirement { get; set; }
public string preamble { get; set; }
public bool Equals(IssueTypeA that)
{
// determine based on the values of the properties
// they must both be the same for equality
if ((this.requirement.Equals(that.requirement)) &&
(this.preamble.Equals(that.preamble)))
{
return true;
}
return false;
}
}
public class IssueTypeB : Issue, IEquatable<IssueTypeB>
{
// some properties specific to this class
public bool Equals(IssueTypeB that)
{
// determine based on the values of the properties
}
}
There is another class, intended to receive objects in the above heirarchy (except the base class, of course), and do some comparison operations with them:
public class Comparer<T> where T : Issue
{
// various comparison methods
public IEnumerable<T> getReferenceChangedIssues(IEnumerable<T> spreadsheetIssues, IEnumerable<T> downloadedIssues)
{
foreach (T spreadsheetRecord in T spreadsheetIssues)
{
foreach (T downloadedIssue in downloadedIssues)
{
// this is the point of failure
// there are cases in which this should be true, but it is not
if (spreadsheetRecord.Equals(downloadedIssue))
{
// the referenceChanged method works fine by itself
// it has been unit tested
if (spreadsheetRecord.referenceChanged(downloadedIssue))
yield return spreadsheetRecord;
}
}
}
}
}
Through unit testing and debugging, it's apparent that the custom Equals methods defined above are not being used correctly by Comparer. Why is this? It is also intended to include methods with some set operations in the future, which will need Equals.
When you implement IEquatable, you really need to override bool Equals(object) and GetHashCode. If you don't do that, things will break in weird ways. This was the stripped-down-est thing I could come up with. I think it should solve your issue (but I can't really tell without your comparison code). If folks point out issues, I'll fix up the code:
public abstract class Issue : IEquatable<Issue>
{
// possibly (not not necessarily) some base properties
// if they are included, make them part of the equality comparison and
// include them in the HashCode calculations
public bool Equals(Issue other)
{
if (other == null)
{
return false;
}
if (this.GetType() != other.GetType())
{
return false;
}
//test local properties and return true/false based on their values
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Issue) obj);
}
}
public class IssueTypeA : Issue, IEquatable<IssueTypeA>
{
public string AName { get; set; } = "My A Name";
public int AValue { get; set; } = 42;
public bool Equals(IssueTypeA other)
{
if (!base.Equals(other))
{
return false;
}
return AName == other.AName && AValue == other.AValue;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((IssueTypeA) obj);
}
//hash-codes need to be consistent once they are calculated - jump through some hoops
private int? _hashCodeValue = default;
public override int GetHashCode()
{
if (!_hashCodeValue.HasValue)
{
_hashCodeValue = $"{AName}{AValue}".GetHashCode();
}
return _hashCodeValue.Value;
}
}
public class IssueTypeB : Issue, IEquatable<IssueTypeB>
{
// some properties specific to this class
public string BName { get; set; } = "My B Name";
public int BValue { get; set; } = 84;
public bool Equals(IssueTypeB other)
{
if (!base.Equals(other))
{
return false;
}
//calculate equality based on local properties and return true/false
return BName == other.BName && BValue == other.BValue;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((IssueTypeB) obj);
}
//hash-codes need to be consistent once they are calculated - jump through some hoops
private int? _hashCodeValue = default;
public override int GetHashCode()
{
if (!_hashCodeValue.HasValue)
{
_hashCodeValue = $"{BName}{BValue}".GetHashCode();
}
return _hashCodeValue.Value;
}
}
This is a better stab at a solution than the first pass. I check for equality based on properties local to each class. I also provide a GetHashCode implementation that is consistent (in the weird way that I believe GetHashCode requires - but in a way that drive Resharper nuts).

How to check if list contains item [duplicate]

Why does this program print "not added" while I think it should print "added"?
using System;
using System.Collections.Generic;
class Element
{
public int id;
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
Element ret = new Element(d);
return ret;
}
public static bool operator ==(Element e1, Element e2)
{
return (e1.id == e2.id);
}
public static bool operator !=(Element e1, Element e2)
{
return !(e1.id == e2.id);
}
}
class MainClass
{
public static void Main(string[] args)
{
List<Element> element = new List<Element>();
element.Add(2);
if(element.Contains(2))
Console.WriteLine("added");
else
Console.WriteLine("not added");
}
}
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌. What is the problem?
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌
No - it uses Equals, which you haven't overridden... so you're getting the default behaviour of Equals, which is to check for reference identity instead. You should override Equals(object) and GetHashCode to be consistent with each other - and for sanity's sake, consistent with your == overload too.
I'd also recommend implementing IEquatable<Element>, which List<Element> will use in preference to Equals(object), as EqualityComparer<T>.Default picks it up appropriately.
Oh, and your operator overloads should handle null references, too.
I'd also strongly recommend using private fields instead of public ones, and making your type immutable - seal it and make id readonly. Implementing equality for mutable types can lead to odd situations. For example:
Dictionary<Element, string> dictionary = new Dictionary<Element, string>();
Element x = new Element(10);
dictionary[x] = "foo";
x.id = 100;
Console.WriteLine(dictionary[x]); // No such element!
This would happen because the hash code would change (at least under most implementations), so the hash table underlying the dictionary wouldn't be able to find even a reference to the same object that's already in there.
So your class would look something like this:
internal sealed class Element : IEquatable<Element>
{
private readonly int id;
public int Id { get { return id; } }
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
return new Element(d);
}
public static bool operator ==(Element e1, Element e2)
{
if (object.ReferenceEquals(e1, e2))
{
return true;
}
if (object.ReferenceEquals(e1, null) ||
object.ReferenceEquals(e2, null))
{
return false;
}
return e1.id == e2.id;
}
public static bool operator !=(Element e1, Element e2)
{
// Delegate...
return !(e1 == e2);
}
public bool Equals(Element other)
{
return this == other;
}
public override int GetHashCode()
{
return id;
}
public override bool Equals(object obj)
{
// Delegate...
return Equals(obj as Element);
}
}
(I'm not sure about the merit of the implicit conversion, by the way - I typically stay away from those, myself.)
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌. What is the problem?
That is correct.
This method [Contains] determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable.Equals method for T (the type of values in the list).
http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.110).aspx
You need to override Equals() as well. Note when you overload Equals(), it is almost always correct to also override GetHashCode().
Override Equals and GetHashCode like:
class Element
{
public int id;
protected bool Equals(Element other)
{
return id == other.id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Element) obj);
}
public override int GetHashCode()
{
return id; //or id.GetHashCode();
}
//..... rest of the class
See: List<T>.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable<T>.Equals method for T (the type of values in the list).

Testing for value equality between two interface instances in c#?

So I have an interface, lets call it IInterface.
public interface IInterface : IEquatable<IInterface>
{
string Name { get; set; }
int Number { get; }
Task<bool> Update();
}
Then I try and implement the interface in Implementation.
public bool Equals(IInterface other)
{
if (other == null) return false;
return (this.Name.Equals(other.Name) && this.Number.Equals(other.Number));
}
public override int GetHashCode()
{
return this.Number.GetHashCode();
}
public override bool Equals(object obj)
{
var other = obj as IInterface ;
return other != null && Equals(other);
}
public static bool operator ==(Implementation left, IInterface right)
{
if (ReferenceEquals(left, right)) return true;
if (ReferenceEquals(left, null)) return false;
return left.Equals(right);
}
public static bool operator !=(Implementation left, IInterface right)
{
return !(left == right);
}
The problem I am running into is in a setter:
public IInterface MyIntf
{
get { return _myIntf; }
set
{
if (_myIntf == value) { return; }
_myIntf = value;
}
Intellisense is showing that the equality test there is testing the references only and treating both left and right as objects. I assume this is because there is no operator overload for ==(IInterface left, IInterface right). Of course, I cannot actually implement that function because == requires one of the sides to match the type of the implementing class. How does one properly make sure two interfaces can be checked for equality against each other?
Update
Got it, you cannot implement == for an interface. I will use Equals. Thanks everyone.
You should explicitly call Equals:
if (_myIntf != null && _myIntf.Equals(value)) { return; }
Implementing IEquatable<T> does not impact the == operator.
Use Equals instead of ==:
public IInterface MyIntf
{
get { return _myIntf; }
set
{
if (_myIntf.Equals(value)) { return; }
_myIntf = value;
}
}

Create an IUserType for a generic option class with nhibernate

I'm looking for a way to create an IUserType for an option type class. Here is the option type class code:
public static class Option
{
public static Option<T> Some<T>(T value)
{
return new Option<T>(value);
}
public static Option<T> None<T>()
{
return new Option<T>();
}
}
public class Option<T>
{
public Option(T value)
{
_value = value;
_isSome = true;
}
public Option()
{
_isSome = false;
}
T _value;
bool _isSome;
public bool IsSome
{
get { return _isSome; }
}
public bool IsNone
{
get { return !_isSome; }
}
public T Value
{
get { return _value; }
}
public T ValueOrDefault(T value)
{
if (IsSome)
return Value;
return value;
}
public override bool Equals(object obj)
{
var temp = obj as Option<T>;
if (temp == null)
return false;
if (this.IsNone && temp.IsNone)
return true;
if (this.IsSome && temp.IsSome)
{
var item1 = this.Value;
var item2 = temp.Value;
return object.Equals(item1, item2);
}
return false;
}
public override int GetHashCode()
{
if (this.IsNone)
return base.GetHashCode() + 23;
return base.GetHashCode() + this.Value.GetHashCode() + 23;
}
}
It is basically just a wrapper around whatever type of T the user wants. It should end up mapping a nullable version of T. I have been unable to find any documentation on doing something like this.
Any help is appreciated.
Here are some articles I have used for the basis of my IUserType classes:
Implementing Custom Types in NHibernate
Generic NHibernate User Type Base Class
Implementing Money Type NHibernate

Categories