Check to see if two user defined objects are equal (C# 2.0)

  • Thread starter Thread starter Jay Douglas
  • Start date Start date
J

Jay Douglas

In C# 2.0 I need to compare instances of an object to see if they are equal
based on an id property.

The object properties are

class Cat
{
int CatId;
string CatName;
}

if (firstCat == secondCat) {
run code because CatId matches in both objects
}

I've tried override the Equals and GetHashCode methods (which never run),
implementing IComparable. I'm not to sure on how to make this code to
work. Any help is appreciated.
 
You shouldn't override the == and != operators for reference types in
..NET.

The "standard" (at least so far as I've read on MSDN) is that == and !=
perform reference comparisons. == returns true if and only if the two
references point to the same object instance.

You _should_ override Equals in your case, and write the following code
to do the comparison:

if (firstCat.Equals(secondCat))

Most .NET programmers expect a reference comparison when they see this:

if (firstCat == secondCat)

they're not expecting an identity comparison or a deep comparison.
 
It seems to be working really well.

Tell me what you think of this documentation:

http://msdn2.microsoft.com/en-us/library/ms173147.aspx

Look at the "Overriding Operator ==" section.

This is what my overridden operators look like:

public static bool operator !=(Cat catA, Cat catB)
{
return !(catA== catB);
}

public static bool operator ==(Cat catA, Cat catB)
{
if (Object.ReferenceEquals(catA, catB))
return true;

if ((object) catA== null || (object) catB == null)
return false;

if (catA.CatId == catB.CatId)
return true;
else
return false;
}
 
Oh, I didn't say it wouldn't work. It's just that it violates a
commonly-held convention among C# programmers, at least according to
MSDN. In fact, the link you indicated says the following:

"When a type is immutable, meaning the data contained in the instance
cannot be changed, overloading operator == to compare value equality
instead of reference equality can be useful because, as immutable
objects, they can be considered the same as long as they have the same
value. Overriding operator == in non-immutable types is not
recommended."

Which is to say that so long as your Cat class does not have (and will
never have) properties with "set" methods, and you can't construct two
Cat objects with the same CatId but differences in other properties,
you can override == and there will be no surprises for other
programmers expecting a reference comparison. Otherwise, MS doesn't
recommend that you override == for reference types.

Since I've never written a reference type that satisfies those two
conditions, I never override == for classes. I just say

if (catA.Equals(catB))

instead.

However, this all depends upon the environment in which you're
programming. If the code is never to be maintained by anyone else then
I suppose it doesn't really matter.

Structs, of course, are a whole other can of worms. I usually provide a
custom implementation of == for struct types.
 
Bruce,

I like where you're going w/ this and I appreciate your feedback. Cat does
have set methods for multiple different properties. Of course this
architecture needs is going to be handed off to other developers for further
development so best practices is something I'm aiming for.

Cat is strictly a data driven object. CatId is unique, at least at the data
table level. I understand that just because CatId is the same in both
objects, it doesn't mean that Name is the same.

BUT, let's say that I have two cat objects and the ID and the Name are the
same. Let's also say that I didn't override the == or != operators. So,
both properties are the same in both objects. If I run (catA == catB) in
code, this compare ALWAYS returns false even though ALL properties that
pertain to the application are identical. This lead me down that path that
I'm taking. What could possibly make my two objects the same.

Possibly this:
Cat catA = new Cat(1);
Cat catB = catA;

(catA == catB)
This should return true, but it's strictly a reference thing, not a data
thing.

So, in my case where the data, especially the key(s) is what makes an object
equal, would the overridden operator be a good practice?
 
Nope. The generally accepted practice, as the MSDN doc points out, is
to use the Equals() method call in place of an == comparison, at least
for reference types.

I'm in exactly the situation you are: I have lots of data objects that
have unique IDs of one kind or another, and for which some properties
are mutable. In my classes, the Equals method does an identity
comparison. That is, if the two CatId's are the same, then the method
returns true, even if other fields are different. In the rare situation
in which I need a deep comparison, I write another routine to do that.
I never use the == comparison, because that compares references.

I tried overriding the == operator but quickly got complaints from
FxCop (if you don't currently use it, it's a wonderful way to stay in
synch with Microsoft standards) about doing that, so I did some digging
and found (I think) the same MSDN page you did, so I removed my ==
overrides and chose to use .Equals() instead.

As I said in another thread recently, I went one step farther and had
each object implement an IKeyed interface that specified a PrimaryKey
attribute. That way each object knows its own primary key and it's much
easier to work with them in a generic fashion. However, that's fodder
for another discussion.

My understanding of == is that the idiom typically isn't used for
reference types. == is assumed by most .NET programmers to be a value
comparison, which for a reference type means comparing reference values
(aka pointers). For reference types you typically compare using
..Equals(), which tells the reader that object fields are being
compared, not just references.

Overriding == also comes with the penalty that you can't take
meaningful advantage of inheritence: you're practically damning
yourself to writing a comparison routine for every new class you build.
Yes, you can take advantage of automatic coercions up the class
hierarchy, but it's not as powerful as overriding the Equals method and
the resulting polymorphic behaviour you get. Maybe that's one of the
reasons that MS doesn't recommend overriding ==.
 
Bruce,

You've made a strong argument and I see the light. =) I'll rework my
methodology. Thanks for your time.
 
Back
Top