Extend the complex number class to test equality in C#

The example Make a complex number class that demonstrates overloaded operators in C# builds a simple Complex class that includes overloaded +, -, *, and / operators that let you combine Complex objects. For example, a program can execute the following code.

Complex A = new Complex(1, 2);
Complex B = new Complex(3, 4);
Complex C = A + B;

Two operators that it didn't define are == and !=. Those are a little different. Note that if you define one of these operators you must define them both. For a simple class such as this one, that's easy because A == B is true when A != B is false.

There are two notions of equality for objects. Reference equality means two references point to the same object. Value equality means two objects contain the same values. For example, if two Employee objects person1 and person2 refer to the same object, they have reference equality. If they refer to different objects that happen to have the same FirstName, LastName, and other properties, then they have value equality.

Note that two objects with reference equality always have value equality because they refer to the same object. The converse is not true.

With all of that in mind, Microsoft has several recommendations about equality.

  • Reference equality operators == and != are already defined by default so if that's what you want, you don't need to do anything else.
  • Microsoft recommends against implementing value equality operators for classes that are not invariant. In other words, if it is possible to change the values of the object's properties after the object is set, then you should stick with reference equality. (I'm not completely sure why they make this recommendation. Perhaps it's because two objects that are equal at one time may become not equal later.)

The Complex class we have been building is not invariant because you can set its Re and Im fields in your code so Microsoft would recommend against using value equality but I'm going to do it anyway because it makes sense for complex numbers. (In fact, Microsoft would probably recommend that the whole thing be converted into a structure instead of a class with Re and Im implemented as read-only properties.)

If you override the == and != operators, you should also override the inherited Equals and GetHashCode methods. If you don't override those methods, Visual Studio issues a warning. The Equals method should basically do whatever == should do. The GetHashCode method should return an int value that code can use for hashing.

Furthermore Microsoft makes these recommendations about the Equals method:

  • Identity: x.Equals(x) should always be true.
  • Commutative: x.Equals(y) should be the same as y.Equals(x).
  • Transitive: If x.Equals(y) is true and y.Equals(z) is true, then x.Equals(z) should return true.
  • Repeated calls to x.Equals(y) should all return the same value if x and y have not changed.
  • The value x.Equals(null) should be false for any (non-null) object x.
  • Equals should not throw exceptions.
  • In addition to overriding Equals(object), you should provide Equals(type) for ths class's type.

The following code shows how this example defines the Complex class's Equals methods.

// Return true if the objects contain the same values.
public bool Equals(Complex
{
if ((object)B == null) return false;
return ((this.Re == B.Re) && (this.Im == B.Im));
}
public override bool Equals(object obj)
{
if (obj == null) return false;
if (!(obj is Complex)) return false;
return this.Equals(obj as Complex);
}

The first method takes a Complex as a parameter. if that parameter is null, the method returns false. Notice that the code converts the parameter to a generic object before using == so it doesn't try to invoke the Complex class's version of ==, which is defined shortly.

The second version of Equals takes an object as a parameter, converts it into a Complex, and calls the first version.

The following code shows how the Complex class overrides the == operator.

// Return A == B.
public static bool operator ==(Complex A, Complex
{
// If both are null or the same object, return true.
if (System.Object.ReferenceEquals(A, ) return true;

// If one is null but not the other, return false.
if (((object)A == null) || ((object)B == null)) return false;

// Compare the field values.
return A.Equals(;
}

The == operator uses the ReferenceEquals method to see if A and B refer to the same object (or they both refer to null). If they do, then their values are equal.

If either A or B is null, they are not equal.

Finally the method calls Equals to see if the objects have the same values.

The following code shows how the Complex class overrides the != operator.

// Return A != B.
public static bool operator !=(Complex A, Complex
{
return !(A == ;
}

This method simply invokes == and negates the result.

The final piece in this example is the implementation of GetHashCode.

// Return a hash code for this object.
public override int GetHashCode()
{
return (Re.GetHashCode() + Im).GetHashCode();
}

This code gets the hash code for the complex number's real part, adds the imaginary part, and then gets the hash code of the result. Exactly what value this has isn't too important as long it's fairly "random" so different "typical" values are unlikely to have the same hash code. In particular, x + yi has a different hash code than y + xi.

(Yes, equality testing is a bit confusing!)

   

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.