views:

10096

answers:

10

Comparing string in C# is pretty simple. In fact there are several ways to do it. I have listed some in the block below. What I am curious about are the differences between them and when one should be used over the others? Should one be avoided at all costs? Are there more I haven't listed?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherStirng) {}

(Note: I am looking for equality in this example, not less than or greater than but feel free to comment on that as well)

+1  A: 

I personally use the .Equals in almost all situations but I am curious as to other's opinions.

Mike Fielden
+13  A: 

From MSDN:

"The CompareTo method was designed primarily for use in sorting or alphabetizing
operations. It should not be used when the primary purpose of the method call is to
determine whether two strings are equivalent. To determine whether two strings are equivalent, call the Equals method."

They suggest using .Equals instead of .ComapreTo when looking solely for equality. I am not sure if there is a difference between .Equals and == for the string class. I will sometimes use .Equals or Object.ReferenceEquals instead of == for my own classes in case someone comes along at a later time and redefines the == operator for that class.

Ed Swangren
Did that ever happened to you? (Redefining == )... I see it as waaaay too defensive programming =)
Juan Manuel
Yes, that's why I now use Object.ReferenceEquals when I am looking for object equality :). It may be a tad over-defensive, but I am not maniacal about it and truthfully this situation doesn't pop up very often.
Ed Swangren
+2  A: 

In the forms you listed here, there's not much difference between the two. CompareTo ends up calling a CompareInfo method that does a comparison using the current culture; Equals is called by the == operator.

If you consider overloads, then things get different. Compare and == can only use the current culture to compare a string. Equals and String.Compare can take a StringComparison enumeration argument that let you specify culture-insensitive or case-insensitive comparisons. Only String.Compare allows you to specify a CultureInfo and perform comparisons using a culture other than the default culture.

Because of its versatility, I find I use String.Compare more than any other comparison method; it lets me specify exactly what I want.

OwenP
A: 

Using .Equals is also a lot easier to read.

hometoast
personally, i think == is a lot easier to read. it's why I don't like java.
FryGuy
Same here, I use Equals only when needed (which is rare).
Dan C.
+1  A: 

Not that performance usually matters with 99% of the times you need to do this, but if you had to do this in a loop several million times I would highly suggest that you use .Equals or == because as soon as it finds a character that doesn't match it throws the whole thing out as false, but if you use the CompareTo it will have to figure out which character is less than the other, leading to slightly worse performance time.

If your app will be running in different countries, I'd recommend that you take a look at the CultureInfo implications and possibly use .Equals. Since I only really write apps for the US (and don't care if it doesn't work properly by someone), I always just use ==.

viggity
+20  A: 

Here are the rules for how these functions work:

stringValue.CompareTo(otherStringValue):

  1. null comes before a string
  2. it uses CultureInfo.CurrentCulture.CompareInfo.Compare, which means it will use a culture-dependant comparison. This might mean that ß will compare equal to SS in Germany, or similar

stringValue.Equals(otherStringValue):

  1. null is not considered equal to anything
  2. unless you specify a StringComparison option, it will use what looks like a direct ordinal equality check, ie. ß is not the same as SS, in any language or culture

stringValue == otherStringValue:

Same as .Equals(..), as it just calls that method.

Object.ReferenceEquals(stringValue, otherStringValue):

Just checks that references are the same, ie. it isn't just two strings with the same contents, you're comparing a string object with itself.


Note that with the options above that use method calls, there are overloads with more options to specify how to compare.

My advice if you just want to check for equality is to make up your mind wether you want to use a culture-dependant comparison or not, and then use .CompareTo or .Equals, depending on the choice.

Lasse V. Karlsen
"stringValue.Equals(otherStringValue): null is not equal to null" Lol, I'd say not. null equals ObjectReferenceNotSet exception.
Kevin
Hah, nice catch, I'll edit the answer.
Lasse V. Karlsen
== is not the same as .Equals()... The == operator calls the static Equals(string a, string b) method (which in turn goes to an internal EqualsHelper to do the comparison. Calling .Equals on a null string gets null reference exc., while on == does not.
Dan C.
On the other hand, .Equals is slightly faster (one less method call internally), but less readable - arguably, of course :).
Dan C.
A: 

One trap is you can't do stringValue.Equals(null) as that assumes you can call a method on null

johnc
+6  A: 

If you are ever curious about differences in BCL methods, Reflector is your friend :-)

I follow these guidelines:

Exact match: EDIT: I previously always used == operator on the principle that inside Equals(string, string) the object == operator is used to compare the object references but it seems strA.Equals(strB) is still 1-11% faster overall than string.Equals(strA, strB), strA == strB, and string.CompareOrdinal(strA, strB). I loop tested with a StopWatch on both interned/non-interned string values, with same/different string lengths, and varying sizes (1B to 5MB).

strA.Equals(strB)

Human-readable match (Western cultures, case-insensitive):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

Human-readable match (All other cultures, insensitive case/accent/kana/etc defined by CultureInfo):

string.Compare(strA, strB, myCultureInfo) == 0

Human-readable match with custom rules (All other cultures):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                            | CompareOptions.IgnoreWidth
                            | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0
max
Nice guidelines!
Nelson Reis
+2  A: 

As Ed said, CompareTo is used for sorting.

There is a difference, however, between .Equals and ==.

== resolves to essentially the following code:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

The simple reason is the following will throw an exception:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

And the following will not:

string a = null;
string b = "foo";

bool equal = a == b;
Jonathan C Dickinson
A: 

with .Equals, you also gain the StringComparison options. very handy for ignoring case and other things.

btw, this will evaluate to false

string a = "myString"; string b = "myString";

return a==b

Since == compares the values of a and b (which are pointers) this will only evaluate to true if the pointers point to the same object in memory. .Equals dereferences the pointers and compares the values stored at the pointers. a.Equals(b) would be true here.

and if you change b to: b = "MYSTRING";

then a.Equals(b) is false, but a.Equals(b, StringComparison.OrdinalIgnoreCase) would be true

a.CompareTo(b) calls the string's CompareTo function which compares the values at the pointers and returns <0 if the value stored at a is less than the value stored at b, returns 0 if a.Equals(b) is true, and >0 otherwise. However, this is case sensitive, I think there are possibly options for CompareTo to ignore case and such, but don't have time to look now. As others have already stated, this would be done for sorting. Comparing for equality in this manner would result in unecessary overhead.

I'm sure I'm leaving stuff out, but I think this should be enough info to start experimenting if you need more details.

David
The a==b part is incorrect. The == operator is effectively overloaded for the String class and it compares the values regardless of the actual references.
Goyuix