implicitly handle operator == when class overrides Equals method

S

Steve Richter

Can I get the C# compiler to implicity implement the relational
operators when my class overrides the Equals method and implements the
IComparer interface?

coding operator== is a bit of work since I have to first cast to
object and compare for null. Then compare for equality. ( is that
true? )

thanks,

( here is the sample class I a working with. No methods are called in
it when operator== is used. )

using System;
using System.Collections.Generic;
using System.Text;

namespace demo_Notepad
{
public class DemoClass1 : IComparer<DemoClass1>
{
public int Row = 0;
public int Column = 0;

public DemoClass1()
{
}

public DemoClass1(int InRow, int InColumn)
{
Row = InRow;
Column = InColumn;
}

public override string ToString()
{
return Row.ToString() + ", " + Column.ToString();
}

public override bool Equals(object obj)
{
if (obj == null)
return false;
else
{
int rv = Compare(this, (DemoClass1)obj);
return (rv == 0);
}
}

#region IComparer<DemoClass1> Members

public int Compare(DemoClass1 InFac1, DemoClass1 InFac2)
{
if (InFac1.Row < InFac2.Row)
return -1;
else if (InFac1.Row > InFac2.Row)
return 1;
else if (InFac1.Column < InFac2.Column)
return -1;
else if (InFac1.Column > InFac2.Column)
return 1;
else
return 0;
}

#endregion

}
}
 
J

Jon Skeet [C# MVP]

Steve Richter said:
Can I get the C# compiler to implicity implement the relational
operators when my class overrides the Equals method and implements the
IComparer interface?

No. You have to implement it yourself.
coding operator== is a bit of work since I have to first cast to
object and compare for null. Then compare for equality. ( is that
true? )

Why would you cast to object?
 
S

Steve Richter

No. You have to implement it yourself.


Why would you cast to object?

the operator== method was being recursively called when I compared
factor1 to null.

public static bool operator ==(DisplayLocation InFac1,
DisplayLocation InFac2)
{
object obj1 = (object)InFac1;
object obj2 = (object)InFac2;
if ((obj1 == null) && (obj2 == null))
return true;
else if (obj1 == null)
return false;
else if (obj2 == null)
return false;
else if ((InFac1.Row == InFac2.Row) &&
(InFac1.Column == InFac2.Column))
return true;
else
return false;
}
 
J

Jon Skeet [C# MVP]

Steve Richter said:
the operator== method was being recursively called when I compared
factor1 to null.

Ah, I see. It's easiest to use object.ReferenceEquals - makes it
clearer (IMO) what you're doing.

One shortcut is to return true if the references are equal, by the way.
It's a slight optimisation for the non-null case (avoids checking each
property) and it copes with the null case as well.

I have a helper method in MiscUtil (in the PartialComparer class) which
makes life a bit easier:

public static bool? Equals<T>(T first, T second)
where T : class
{
if (first==second)
{
return true;
}
if (first==null || second==null)
{
return false;
}
return null;
}

You can then do:

public static bool operator ==(DisplayLocation first,
DisplayLocation second)
{
return PartialComparer.Equals(first, second) ??
(first.Row==second.Row &&
first.Column==second.Column);
}
 
J

Jeroen Mostert

Steve said:
Can I get the C# compiler to implicity implement the relational
operators when my class overrides the Equals method and implements the
IComparer interface?
Nope. Equals and the ICompare* interfaces are not special from a language
point of view, and operator overloading is orthogonal to it. This is a bit
unfortunate since you'll have to be careful to make it all mean the same thing.
coding operator== is a bit of work since I have to first cast to
object and compare for null. Then compare for equality. ( is that
true? )

public override bool Equals(object obj)
{
if (obj == null)
return false;
else
{
int rv = Compare(this, (DemoClass1)obj);
return (rv == 0);
}
}
This is an incorrect implementation since it may throw an
InvalidCastException. Equals() isn't allowed to do that. Overriding Equals()
is a fairly subtle affair. The MSDN contains a sample that shows how to do it:

public override bool Equals(object obj) {
if (obj == null || this.GetType() != obj.GetType()) return false;
return Compare(this, (DemoClass1) obj) == 0;
}

If you also overload == to provide instance equivalence rather than
reference equivalence, you should delegate to that:

public override bool Equals(object obj) {
if (obj == null || this.GetType() != obj.GetType()) return false;
return this == (DemoClass1) obj;
}

public static bool operator==(DemoClass1 d1, DemoClass2 d2) {
return Compare(d1, d2) == 0;
}
public int Compare(DemoClass1 InFac1, DemoClass1 InFac2)
{
if (InFac1.Row < InFac2.Row)
return -1;
else if (InFac1.Row > InFac2.Row)
return 1;
else if (InFac1.Column < InFac2.Column)
return -1;
else if (InFac1.Column > InFac2.Column)
return 1;
else
return 0;
}

Actually, if your class has only one "natural" comparison order,
implementing IComparer is not the way to go. Implement IComparable instead.
Then Comparer<DemoClass1>.Default will return an instance that uses this.
 
S

Steve Richter

Nope. Equals and the ICompare* interfaces are not special from a language
point of view, and operator overloading is orthogonal to it. This is a bit
unfortunate since you'll have to be careful to make it all mean the same thing.

thank you both for the answers.

as an aside, this is evidence to me there is a place for a "C# simple"
language. Maybe that is what VB is for. Only I prefer the syntax of
C#.

-Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top