Geeks With Blogs
Will Smith The Blog in Black

I re-learned something seemingly trivial today.  The == operator is not the same as Equals (more specifically, the default implementation of the == operator).

I overrode Equals for one of my classes and couldn't figure out why my code wasn't working.  Then I realized that == performs a reference comparison, not a value comparison.  I will have to keep this in mind any time I am comparing objects.  Generally, I will want to use the Equals method.

When I first encountered the problem, I decided to implement my own version of the == (and !=) operator.  The new implementation would perform a value comparison.  I felt uncomfortable with this and decided to do a bit of research.  Microsoft recommends you only override immutable types in this manner.  An immutable type is any type that cannot be changed after instantiation.  My class is not immutable.  So, I decided to take the == implementation out.

I think we easily can be confused because, many built in value types implement value comparison with the == operator.  And to add further complication, you have to consider if a string is "interned".  About the only time you are dealing with interned strings is when you are using literals.  If you are retrieving a string from a database, then it won't be interned.

Take a look at the NUnit test below.  I purposefully did not use AreEqual, AreSame, AreNotSame because I wanted to demonstrate more clearly how the .net operators and methods work.

   1: [Test]
   2: public void TestValueComparison()
   3: {
   4:     int a = 1;
   5:     int b = 1;
   6:     Assert.IsTrue( a == b );
   7:     Assert.IsTrue( a.Equals( b ) );
   8:     Assert.IsFalse( Object.ReferenceEquals( a, b ) );
   9:     //Interned strings    
  10:     string x = "test";
  11:     string y = "test";
  12:     Assert.IsTrue( x == y );
  13:     Assert.IsTrue( x.Equals( y ) );
  14:     Assert.IsTrue( Object.ReferenceEquals( x, y ) );
  15:     //Non-interned strings    
  16:     string p = new string( 'a', 3 );
  17:     string q = new string( 'a', 3 );
  18:     Assert.IsTrue( p == q );
  19:     Assert.IsTrue( p.Equals( q ) );
  20:     Assert.IsFalse( Object.ReferenceEquals( p, q ) );
  21:     //Manually interning the strings    
  22:     p = string.Intern( p );
  23:     q = string.Intern( q );
  24:     Assert.IsTrue( Object.ReferenceEquals( p, q ) );
  25: }

So, generally speaking, if you want to perform a value comparison of reference types, you want to use the Equals method.

Cheers.

Tags:
Posted on Thursday, May 29, 2008 10:38 AM .Net , Design , C# | Back to top


Comments on this post: .Net Equality

# re: .Net Equality
Requesting Gravatar...
Hi Will.

I've become a big fan of overriding equality, myself. You brought up a good point regarding only doing the == and != for immutable types, though. The thing that someone needs to watch out for with mutable types isn't so much equality, as it is GetHashCode(), which .NET warns you to override as well. If without thinking you use some properties in your GetHashCode, and one of those properties is changed, your GetHashCode changes. Any structure that depends on GetHashCode() (like dictionaries) fails.

This post describes it well...

http://blogs.msdn.com/abhinaba/archive/2007/10/18/mutable-objects-and-hashcode.aspx
Left by Mark Hildreth on Jun 04, 2008 3:53 AM

# re: .Net Equality
Requesting Gravatar...
I didn't even mention GetHashCode because its second nature to implement it when I implement Equals. I am glad Mark mentioned it though. I can still remember when I asked myself why Microsoft added that infernal compiler warning.

Nice reference too, Mark. Thanks.
Left by Will Smith on Jun 04, 2008 11:05 PM

Your comment:
 (will show your gravatar)


Copyright © Will Smith | Powered by: GeeksWithBlogs.net