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.
[Test]
public void TestValueComparison()
{
int a = 1;
int b = 1;
Assert.IsTrue( a == b );
Assert.IsTrue( a.Equals( b ) );
Assert.IsFalse( Object.ReferenceEquals( a, b ) );
//Interned strings
string x = "test";
string y = "test";
Assert.IsTrue( x == y );
Assert.IsTrue( x.Equals( y ) );
Assert.IsTrue( Object.ReferenceEquals( x, y ) );
//Non-interned strings
string p = new string( 'a', 3 );
string q = new string( 'a', 3 );
Assert.IsTrue( p == q );
Assert.IsTrue( p.Equals( q ) );
Assert.IsFalse( Object.ReferenceEquals( p, q ) );
//Manually interning the strings
p = string.Intern( p );
q = string.Intern( q );
Assert.IsTrue( Object.ReferenceEquals( p, q ) );
}
So, generally speaking, if you want to perform a value comparison of reference types, you want to use the Equals method.
Cheers.