When Equals ≠ ==

by Michael S. Kaplan, published on 2007/02/18 22:31 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2007/02/18/1710716.aspx

There are two different ways to talk about equality in C# -- one with the Equals method, the other with the operator ==.

(There is also sometimes a ReferenceEquals method and other times a Compare method one could use looking for a return value of 0, but we'll leave them aside for now)

The question that came in the other day from Bertrand:

We recently had a bug that was caused by a direct == comparison between a CultureInfo instance and CultureInfo.InvariantCulture. == can return false even though the instance is the invariant culture. Using culture.Equals returns the right result consistently and should be used whenever doing culture info comparisons instead of ==.

Behind the scenes, the CultureInfo class does not override the == operator, so it us doing a reference comparison to look whether two objects are referencing one instance rather than two different instances that happen to point to the same object. In many situations the difference can be quite significant in terms of behavior, though in the case of Invariant this is not true since the object cannot be modified. Which perhaps helps to add to the confusion a bit.

And the exact semantic of the CultureInfo.Equals method is simple enough:

  1. Do the two cultures have the same CultureInfo.Name ?
  2. Does the CompareInfo.Equals method when pointed at the respective CompareInfo objects of the two cultures return true?
    This method has its own two subparts to it:
    1. Are the two CompareInfo.LCID values the same?
    2. Do the two CompareInfo objects have the same CompareInfo.Name?

The addition of the CompareInfo stuff happened first in 2.0, in order to support the special GetCultureInfo overload that allows them to be different, added for SQLCLR consistency (which I still haven't talked about, though I will some day, I promise!).

There are some interesting side effects of the implementation:

I guess what is important here is to step back and try and figure out what one is trying to do in checking for equality. That is the only way to make sure one is not surprised by the answer one gets....


This post brought to you by  (U+2260, a.k.a. NOT EQUAL TO)

# josh on 19 Feb 2007 4:06 PM:

Lisp still wins:  eq, eql, equal, equalp

# Michael S. Kaplan on 19 Feb 2007 4:18 PM:

Hmmm... is there a Lisp.Net?

# Miral on 19 Feb 2007 5:26 PM:

I just think the whole situation of which operators get implemented and which ones don't is completely braindead in .NET.

The == operator should automatically call .Equals, since they're always logically equivalent (if nobody implements Equals, then it gets Object.Equals, which does reference comparison; if you really wanted reference comparison for something that does implement Equals then you can use Object.ReferenceEquals, which is more explicit).

The <, > operators etc should automatically call into the IComparable interface implementations, if they exist.  (If they don't exist, then using the operators should be invalid.)

I can't see any sane reason why you'd implement < without >, for example, yet this almost seems to be encouraged in the current syntax.  Ok, it's slightly more C++-like, but C++ operator overloading is *nuts*, so that's not a good thing.

# Michael S. Kaplan on 19 Feb 2007 6:06 PM:

Perhaps new operators should be defined for ∈, ∉, ∋, ∌, ≡, ≢, and ≣. :-)

# mihailik on 20 Feb 2007 8:57 AM:

It is the stupidies thing to introduce in .NET Framework!

The designer of the class MUST know what meant to be equal. And this thing should be consistently coded in BOTH operator== and Equals/GetHashCode.

Since both GetHashCode and Equals works same way, I conclude somebody shall be sacked by skipping operator== in the class.

There were bazillions reasons to invent new sorts of comparisons in .NET Framework. But God blessed those reasons were shut down hardly and enthusiastic inventors fined violently.

So, please, keep it simple and throw this 'special comparison' thing out of sight. Nobody really cares about what a cool creative field/flag makes CultureInfo instances different. 1 bit wins.

go to newer or older post, or back to index or month or day