#421 – Value Equality and IComparable Example

Here’s a full example of a reference type that supports value equality semantics and implements both IEquatable and IComparable.

```    public class Rectangle : IEquatable<Rectangle>, IComparable<Rectangle>
{
public int Height { get; set; }
public int Width { get; set; }

public Rectangle(int height, int width)
{
Height = height;
Width = width;
}

public override bool Equals(object obj)
{
return this.Equals(obj as Rectangle);
}

public override int GetHashCode()
{
return Height.GetHashCode() ^ Width.GetHashCode();
}

public bool Equals(Rectangle r)
{
if (ReferenceEquals(r,null))
return false;

return ((Height == r.Height) && (Width == r.Width) ||
(Height == r.Width) && (Width == r.Height));
}

public static bool operator ==(Rectangle r1, Rectangle r2)
{
if (ReferenceEquals(r1, null))
{
return ReferenceEquals(r2, null) ? true : false;
}

return r1.Equals(r2);
}

public static bool operator !=(Rectangle r1, Rectangle r2)
{
return !(r1 == r2);
}

// Result:
//  < 0 : this instance less than r
//  = 0 : this instance equivalent to r
//  > 0 : this instance greater than r
public int CompareTo(Rectangle r)
{
if (ReferenceEquals(r, null))
return 1;

if (this.Equals(r))
return 0;

else if (this.Area() == r.Area())
return this.Width - r.Width;

else
return this.Area() - r.Area();
}

public static bool operator <(Rectangle r1, Rectangle r2)
{
if (ReferenceEquals(r1, null))
return false;

else
return (r1.CompareTo(r2) < 0) ? true : false;
}

public static bool operator >(Rectangle r1, Rectangle r2)
{
if (ReferenceEquals(r1, null))
return false;

else
return (r1.CompareTo(r2) > 0) ? true : false;
}

public static bool operator <=(Rectangle r1, Rectangle r2)
{
return (r1 < r2) || (r1 == r2);
}

public static bool operator >=(Rectangle r1, Rectangle r2)
{
return (r1 > r2) || (r1 == r2);
}

public int Area()
{
return Height * Width;
}
}
```

#420 – Laundry List for Implementing Value Equality and IComparable

To implement value equality (equivalence) in a reference type, you should do the following:

• Override Object.Equals
• In Object.Equals, call the type-specific Equals method using the as operator
• Implement IEquatable<T> by adding a type-specific Equals method
• Check for null using ReferenceEquals method
• Call base class’ Equals method to compare fields that exist in the base class if it also checks for value equality
• Check for equivalence by comparing individual fields
• Override GetHashCode, generating a hash code based on fields used for equivalence
• Overload == operator
• Check for 1st parameter being null, compare to 2nd parameter
• Call 1st parameter’s type-specific Equals method
• Overload != operator, invoking the == operator
• Implement IComparable<T>, adding a CompareTo method
• Check for equivalence using Equals method, then compare individual fields
• Overload < and > operators
• Check for 1st parameter being null
• Call 1st parameter’s CompareTo method
• Overload <= and >= operators
• Calculate a result using the <, > and == operators

#417 – Provide a Type-Specific Equals Method for Value Equality

When you are implementing value equality in a type, you typically override the Equals method that is defined in System.Object.  It has the following signature:

```        public override bool Equals(object obj)
```

You should also add a type-specific Equals method.  For completeness, you can indicate that your class implements IEquatable<T>, which includes the type-specific Equals method.

```    public class Dog : IEquatable<Dog>
```

Below is a complete example, showing us the override of System.Object.Equals, as well as the type-specific Equals method.  Note that the generic Equals method calls the type-specific version.

```        // System.Object.Equals
public override bool Equals(object obj)
{
return this.Equals(obj as Dog);
}

// IEquatable<Dog>.Equals
public bool Equals(Dog d)
{
if (d == null)
return false;

return (Name == d.Name) && (Age == d.Age);
}
```