[c#] Why would you use String.Equals over ==?

I recently was introduced to a large codebase and noticed all string comparisons are done using String.Equals() instead of ==

What's the reason for this, do you think?

This question is related to c# string equals

The answer is


I want to add that there is another difference. It is related to what Andrew posts.

It is also related to a VERY annoying to find bug in our software. See the following simplified example (I also omitted the null check).

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return numberTextBoxTextValue.Equals(SPECIAL_NUMBER)
}

This will compile and always return false. While the following will give a compile error:

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return (numberTextBoxTextValue == SPECIAL_NUMBER);
}

We have had to solve a similar problem where someone compared enums of different type using Equals. You are going to read over this MANY times before realising it is the cause of the bug. Especially if the definition of SPECIAL_NUMBER is not near the problem area.

This is why I am really against the use of Equals in situations where is it not necessary. You lose a little bit of type-safety.


String.Equals does offer overloads to handle casing and culture-aware comparison. If your code doesn't make use of these, the devs may just be used to Java, where (as Matthew says), you must use the .Equals method to do content comparisons.


Both methods do the same functionally - they compare values.
As is written on MSDN:

But if one of your string instances is null, these methods are working differently:

string x = null;
string y = "qq";
if (x == y) // returns false
    MessageBox.Show("true");
else
    MessageBox.Show("false");

if (x.Equals(y)) // returns System.NullReferenceException: Object reference not set to an instance of an object. - because x is null !!!
    MessageBox.Show("true");
else
    MessageBox.Show("false");

There's a writeup on this article which you might find to be interesting, with some quotes from Jon Skeet. It seems like the use is pretty much the same.

Jon Skeet states that the performance of instance Equals "is slightly better when the strings are short—as the strings increase in length, that difference becomes completely insignificant."


It's entirely likely that a large portion of the developer base comes from a Java background where using == to compare strings is wrong and doesn't work.

In C# there's no (practical) difference (for strings) as long as they are typed as string.

If they are typed as object or T then see other answers here that talk about generic methods or operator overloading as there you definitely want to use the Equals method.


There is practical difference between string.Equals and ==

bool result = false;

object obj = "String";    
string str2 = "String";
string str3 = typeof(string).Name;
string str4 = "String";
object obj2 = str3;

// Comparision between object obj and string str2 -- Com 1
result = string.Equals(obj, str2);// true
result = String.ReferenceEquals(obj, str2); // true
result = (obj == str2);// true

// Comparision between object obj and string str3 -- Com 2
result = string.Equals(obj, str3);// true
result = String.ReferenceEquals(obj, str3); // false
result = (obj == str3);// false

// Comparision between object obj and string str4 -- Com 3
result = string.Equals(obj, str4);// true
result = String.ReferenceEquals(obj, str4); // true
result = (obj == str4);// true

// Comparision between string str2 and string str3 -- Com 4
result = string.Equals(str2, str3);// true
result = String.ReferenceEquals(str2, str3); // false
result = (str2 == str3);// true

// Comparision between string str2 and string str4 -- Com 5
result = string.Equals(str2, str4);// true
result = String.ReferenceEquals(str2, str4); // true
result = (str2 == str4);// true

// Comparision between string str3 and string str4 -- Com 6
result = string.Equals(str3, str4);// true
result = String.ReferenceEquals(str3, str4); // false
result = (str3 == str4);// true

// Comparision between object obj and object obj2 -- Com 7
result = String.Equals(obj, obj2);// true
result = String.ReferenceEquals(obj, obj2); // false
result = (obj == obj2);// false

Adding Watch

obj     "String" {1#}   object {string}
str2    "String" {1#}   string
str3    "String" {5#}   string
str4    "String" {1#}   string
obj2    "String" {5#}   object {string}

Now look at {1#} and {5#}

obj, str2, str4 and obj2 references are same.

obj and obj2 are object type and others are string type

Conclusion:

  1. com1: result = (obj == str2);// true
    • compares object and string so performs a reference equality check
    • obj and str2 point to the same reference so the result is true
  2. com2: result = (obj == str3);// false
    • compares object and string so performs a reference equality check
    • obj and str3 point to the different references so the result is false
  3. com3: result = (obj == str4);// true
    • compares object and string so performs a reference equality check
    • obj and str4 point to the same reference so the result is true
  4. com4: result = (str2 == str3);// true
    • compares string and string so performs a string value check
    • str2 and str3 are both "String" so the result is true
  5. com5: result = (str2 == str4);// true
    • compares string and string so performs a string value check
    • str2 and str4 are both "String" so the result is true
  6. com6: result = (str3 == str4);// true
    • compares string and string so performs a string value check
    • str3 and str4 are both "String" so the result is true
  7. com7: result = (obj == obj2);// false  - compares object and object so performs a reference equality check      - obj and obj2 point to the different references so the result is false

There is one subtle but very important difference between == and the String.Equals methods:

class Program
{
    static void Main(string[] args)
    {
        CheckEquality("a", "a");
        Console.WriteLine("----------");
        CheckEquality("a", "ba".Substring(1));
    }

    static void CheckEquality<T>(T value1, T value2) where T : class
    {
        Console.WriteLine("value1: {0}", value1);
        Console.WriteLine("value2: {0}", value2);

        Console.WriteLine("value1 == value2:      {0}", value1 == value2);
        Console.WriteLine("value1.Equals(value2): {0}", value1.Equals(value2));

        if (typeof(T).IsEquivalentTo(typeof(string)))
        {
            string string1 = (string)(object)value1;
            string string2 = (string)(object)value2;
            Console.WriteLine("string1 == string2:    {0}", string1 == string2);
        }
    }
}

Produces this output:

value1: a
value2: a
value1 == value2:      True
value1.Equals(value2): True
string1 == string2:    True
----------
value1: a
value2: a
value1 == value2:      False
value1.Equals(value2): True
string1 == string2:    True

You can see that the == operator is returning false to two obviously equal strings. Why? Because the == operator in use in the generic method is resolved to be the op_equal method as defined by System.Object (the only guarantee of T the method has at compile time), which means that it's reference equality instead of value equality.

When you have two values typed as System.String explicitly, then == has a value-equality semantic because the compiler resolves the == to System.String.op_equal instead of System.Object.op_equal.

So to play it safe, I almost always use String.Equals instead to that I always get the value equality semantics I want.

And to avoid NullReferenceExceptions if one of the values is null, I always use the static String.Equals method:

bool true = String.Equals("a", "ba".Substring(1));

I've just been banging my head against a wall trying to solve a bug because I read this page and concluded there was no meaningful difference when in practice there is so I'll post this link here in case anyone else finds they get different results out of == and equals.

Object == equality fails, but .Equals succeeds. Does this make sense?

string a = "x";
string b = new String(new []{'x'});

Console.WriteLine("x == x " + (a == b));//True
Console.WriteLine("object x == x " + ((object)a == (object)b));//False
Console.WriteLine("x equals x " + (a.Equals(b)));//True
Console.WriteLine("object x equals x " + (((object)a).Equals((object)b)));//True