I\'m working on a C# project on which, until now, I\'ve used immutable objects and factories to ensure that objects of type Foo
can always be compared for equal
According to Microsofts own best practises the outcome of the Equals method and the equals (==) overload should be the same.
CA2224: Override equals on overloading operator equals
I believe the standard is that for most types, .Equals checks object similarity, and operator ==
checks reference equality.
I believe best practice is that for immutable types, operator ==
should be checking for similarity, as well as .Equals
. And if you want to know if they really are the same object, use .ReferenceEquals
. See the C# String
class for an example of this.
It definitely smells. When overloading ==
you should make sure that both Equals()
and GetHashCode()
are also consistent. See the MSDN guidelines.
And the only reason that this seems OK at all is that you describe your type as immutable.
Sample showing how to implement this according to MSFT guidelines (below). Notice, when overriding Equals you also need to override GetHashCode(). Hope this helps folks.
public class Person
{
public Guid Id { get; private set; }
public Person(Guid id)
{
Id = id;
}
public Person()
{
Id = System.Guid.NewGuid();
}
public static bool operator ==(Person p1, Person p2)
{
bool rc;
if (System.Object.ReferenceEquals(p1, p2))
{
rc = true;
}
else if (((object)p1 == null) || ((object)p2 == null))
{
rc = false;
}
else
{
rc = (p1.Id.CompareTo(p2.Id) == 0);
}
return rc;
}
public static bool operator !=(Person p1, Person p2)
{
return !(p1 == p2);
}
public override bool Equals(object obj)
{
bool rc = false;
if (obj is Person)
{
Person p2 = obj as Person;
rc = (this == p2);
}
return rc;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
For immutable types I don't think there is anything wrong with having ==
overloaded to support value equality. I don't think I'd override ==
without overriding Equals
to have the same semantics however. If you do override ==
and need to check reference equality for some reason, you can use Object.ReferenceEquals(a,b)
.
See this Microsoft article for some useful guidelines
There's a big difference between overloading ==
and overriding Equals.
When you have the expression
if (x == y) {
The method that will be used to compare variables x and y is decided at compile time. This is operator overloading. The type used when declaring x and y is used to define which method is used to compare them. The actual type within x and y (i.e., a subclass or interface implementation) is irrelevant. Consider the following.
object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference
if (x == y) { // evaluates to FALSE
and the following
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x == y) { // evaluates to TRUE
This demonstrates that the type used to declare the variables x and y is used to determine which method is used to evaluate ==.
By comparison, Equals is determined at runtime based on the actual type within the variable x. Equals is a virtual method on Object that other types can, and do, override. Therefore the following two examples both evaluate to true.
object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference
if (x.Equals(y)) { // evaluates to TRUE
and the following
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x.Equals(y)) { // also evaluates to TRUE