In this post I present a way to implement equality between objects. Implicit support for == and != operators. There is the big writeup on Guidelines for Overloading Equals() and Operator == (C# Programming Guide) at MSDN that you can follow when you implement Equals() method for your custom type. But Cinchoo framework provides easy way to accomplish this. Read below on how to do it.
Reference Types
The Equals method is just a virtual one defined in System.Object, and overridden by whichever classes choose to do so. By default it provides reference equality.
The == operator is an operator which can be overloaded by classes, but which usually has identity behavior. The == operator has not been overloaded, it compares whether two references refer to the same object – which is exactly what the implementation of Equals does in System.Object.
Cinchoo framework provides abstraction through ChoEquatableObject<T> class, which exposes Equals() method, == and != operators for you. The default implementation of Equals() method uses reflection to make the comparison. This can be overloaded in your derived class.
1. Add reference to Cinchoo.Core.dll assembly
2. Namespace Cinchoo.Core
For the sample class derived from ChoEuatableObject<T>, uses the default implementation of object equality
public class Security : ChoEquatableObject<Security>
{
public string Symbol;
[ChoIgnoreEqual]
public double Price;
[ChoIgnoreEqual]
public int Qty;
}
ChoIgnoreEqual tell the framework to ignore those members while making equality of the objects. In the above Security class, it only uses Symbol member while making equality and ignore other members.
If you worry about performance of using reflection when making equality of objects, you can consider overriding Equals() method as below
public class Security : ChoEquatableObject<Security>
{
public string Symbol;
public double Price;
public int Qty;
public override bool Equals(Security other)
{
if (object.ReferenceEquals(other, null))
return false;
return Symbol == other.Symbol;
}
}
The sample test code below
class Program
{
static void Main(string[] args)
{
Security sec1 = new Security() { Symbol="AAPL", Price = 555.10, Qty = 10 };
Security sec2 = new Security() { Symbol="AAPL", Price = 655.55, Qty = 500 };
Console.WriteLine("ChoObject.Equals() : " + ChoObject.Equals(sec1, sec2));
Console.WriteLine("Object.Equals() : " + sec1.Equals(sec2));
Console.WriteLine("== operator: " + (sec1 == sec2));
Console.WriteLine("!= operator: " + (sec1 != sec2));
}
}
The output will be
ChoObject.Equals() : True
Object.Equals() : True
== operator: True
!= operator: False
In cases where you do not want to derive from ChoEquableObject<T> or your class already in the inheritance chain, please follow the next section in implementing object equality.
Value Types
Value types do not provide an overload for == by default. However, most of the value types provided by the framework provide their own overload. The default implementation of Equals for a value type is provided by ValueType , and uses reflection to make the comparison.
Below is the way to implement ValueType equality or a reference type equality through Interface
public struct Security : IEquatable<Security>
{
public string Symbol;
public double Price;
public int Qty;
#region IEquatable<Security> Members
public override bool Equals(object obj)
{
return Equals((Security)obj);
}
public bool Equals(Security other)
{
if (object.ReferenceEquals(other, null))
return false;
return Symbol == other.Symbol;
}
public static bool operator ==(Security a, Security b)
{
return ChoObject.Equals(a, b);
}
public static bool operator !=(Security a, Security b)
{
return !ChoObject.Equals(a, b);
}
#endregion
}