Why we have different output for below cases:
object obj = "Int32";
string str1 = "Int32";
string str2 = typeof(int).Name;
Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // false !?
The answer to this is quite simple:
When you compare an object with a string, a reference comparison is used, which will only be true if both objects have the same reference.
When you compare strings a string comparison is used, which will be true if the string contents are the same regardless of whether they are the same reference.
In your third comparison you are using an object comparison where you are comparing two strings with identical contents but with different references, so it will return false.
The added complication is that the first two strings have the same reference because they are compile-time constants and have been interned by the compiler so that they refer to the same string in memory.
I've annotated your original code with this explanation:
object obj = "Int32"; // As a compile-time constant string, this will be interned.
string str1 = "Int32"; // This is also interned, so has the same reference as obj
string str2 = typeof(int).Name; // Same contents as str1, but a different reference
// (created at runtime, so it wasn't interned)
Console.WriteLine(obj == str1); // Reference comparison: true because the references are the same
Console.WriteLine(str1 == str2); // String comparison: true because the string contents are the same.
Console.WriteLine(obj == str2); // Reference comparison: false because the references different.
Also:
If you are using Resharper it actually warns you for the first and last comparison, saying: "Possible unintended reference comparison".
You can get the same result by declaring str2 as follows:
string str2 = string.Concat("Int", "32");
The obj == str2 line used reference comparison. Whereas the obj == str1 line did not.
Why?
The string type in .NET is an implicit reference type. But it's not at the same time. It's one of those types that is technically a reference type, but it's been programmed to act like a value type, and is immutable, meaning it is not directly modified.
When you create a new string, a reference is allocated for it and that reference is what your string variable holds. You get to do all sorts of things with that string, but you can never change it. If you reassign the value it will merely create a new reference.
In this instance, the obj == str1 line used reference comparison, but the references actually matched. Because they were both hard-coded, the compiler, and .NET, can use the same reference for each. (As we said before, strings are immutable.) You should read the interning link Matthew posted for more information on that.
So, if the strings match, why did .NET create a different reference?
Consider the significant amount of objects you could create in memory. If, at any time, you created a new string and .NET went through all of the other strings to find one that matched, your programme would be phenomenally slow. You would barely get any real work done.
So, .NET optimizes this away. If you change your code a bit, you'll see what I mean.
object obj = "Int32";
string str1 = typeof(int).Name;
string str2 = typeof(int).Name;
Console.WriteLine(obj == str1); // false
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // false !?
The str1 == str2 line still returns true, because it's actually comparing the strings, whereas the obj == str1 line is now false, because it's comparing the references of those as well.
Related
Edit:
Why this question is not duplicate?
I'm not asking difference between .Equals() and ==. I'm asking how does actually == work. I mean, when I created strings using different method, I should have seen different result. But I see same result.
I was looking into == operator in c#. To my surprise it gave same result for following codes (contrary to JAVA). But according to this, == is for reference check and I should see different result for my code then why do I see same result for both of them? Shouldn't I see different results for my piece of codes? Is it because new String() in c# doesn't generate new reference?
String s = "abc";
String s1 = "abc";
Console.WriteLine("Expected output: True, Actual output: " + (s1==s).ToString());
Output
Expected output: True, Actual output: True
Another code check
String s2 = new String("abc".ToCharArray());
String s3 = new String("abc".ToCharArray());
Console.WriteLine("Expected output: False, Actual output: " + (s2 == s3).ToString());
Output
Expected output: False, Actual output: True
Note: I understand difference reference & value check. I've tried result with ReferenceEquals and it shows expected result to me.
Normally for reference types == operator do check for reference equality.
String is also a reference type but in String class == operator is overloaded to check for content equality and not reference equality.
It says and I quote
Determines whether two specified strings have the same value.
Read here https://msdn.microsoft.com/en-us/library/system.string.op_equality(v=vs.110).aspx
FYI, in string != operator is also oveloaded to check for string content inequality.
In c# operator == for string compares value, not reference.
In C# strings are immutable and managed. In theory that would mean the concatenation of any strings A and B would cause the allocation of a new buffer however this is all pretty obfuscated. When you concatenate with the identity (the empty string) the reference maintains intact. Is this a compile time optimization or is the overloaded assignment operator making the decision to not realloc at runtime? Furthermore, how does the runtime/compiler handle s2's value/allocation when I modify the value of s1? My program would indicate that the memory at the original address of s1 remains intact (and s2 continues pointing there) while a relloc occurs for the new value and then s1 is pointed there, is this an accurate description of what happens under the covers?
Example program;
static void Main(string[] args)
{
string s1 = "Some random text I chose";
string s2 = s1;
string s3 = s2;
Console.WriteLine(Object.ReferenceEquals(s1, s2)); // true
s1 = s1 + "";
Console.WriteLine(Object.ReferenceEquals(s1, s2)); // true
Console.WriteLine(s2);
s1 = s1 + " something else";
Console.WriteLine(Object.ReferenceEquals(s1, s2)); // false cause s1 got realloc'd
Console.WriteLine(Object.ReferenceEquals(s2, s3));
Console.WriteLine(s2);
Console.ReadKey();
}
When you concatenate with the identity (the empty string) the reference maintains intact. Is this a compile time optimization or is the overloaded assignment operator making the decision to not realloc at runtime?
It is both a compile time optimization and also an optimization performed in the implementation of the overloaded concatenation operator. If you concat two compile time literals, or concat a string known to be null or empty at compile time, the concatenation is done at compile time, and then potentially interned, and will therefore be reference equal to any other compile time literal string that has the same value.
Additionally, String.Concat is implemented such that if you concat a string with either null or an empty string, it just returns the other string (unless the other string was null, in which case it returns an empty string). The test you already have demonstrates this, as you're concatting a non-compile time literal string with an empty string and it's staying reference equal.
Of course if you don't believe your own test, you can look at the source to see that if one of the arguments is null then it simply returns the other.
if (IsNullOrEmpty(str0)) {
if (IsNullOrEmpty(str1)) {
return String.Empty;
}
return str1;
}
if (IsNullOrEmpty(str1)) {
return str0;
}
When you concatenate with the identity (the empty string) the reference maintains intact. Is this a compile time optimization or is the overloaded assignment operator making the decision to not realloc at runtime?
This is a run-time optimization. Here is how it is implemented in Mono:
public static String Concat(String str0, String str1) {
Contract.Ensures(Contract.Result() != null);
Contract.Ensures(Contract.Result().Length ==
(str0 == null ? 0 : str0.Length) +
(str1 == null ? 0 : str1.Length));
Contract.EndContractBlock();
// ========= OPTIMIZATION BEGINS ===============
if (IsNullOrEmpty(str0)) {
if (IsNullOrEmpty(str1)) {
return String.Empty;
}
return str1;
}
if (IsNullOrEmpty(str1)) {
return str0;
}
// ========== OPTIMIZATION ENDS =============
int str0Length = str0.Length;
String result = FastAllocateString(str0Length + str1.Length);
FillStringChecked(result, 0, str0);
FillStringChecked(result, str0Length, str1);
return result;
}
The compiler may produce additional optimizations of its own - for example, concatenating two string literals produces a new literal value at compile time, without calling string.Concat. This is not different from C#'s handling of other expressions that include compile-time constants of other data types, though.
Furthermore, how does the runtime/compiler handle s2's value/allocation when I modify the value of s1?
s1 and s2 are independent references to the same string object, which is immutable. Reassigning another object to one of them does not change the other reference.
It is a decision by the String.Concat function not to concat the string. It checks whether s1 is null and assigns "" to s1 if yes.
s1 = s1 + "";
gets optimized by the comiler.
s1 = s1 ?? "";
If you want to learn more check out this link
String concatenation is specified to return a string whose sequence of characters is the concatenation of the sequences encapsulated by the string representations of the things being concatenated. In cases where no existing string contains the proper sequence of characters, the concatenation code will need to create a new one; further, even in cases where an existing string might contain the proper sequence of characters, it will usually be faster for the computer to create a new string than try to find the existing one. I believe, however, that concatenation is allowed to return an existing string in any case where it can quickly find one that contains the proper characters, and in the case of concatenating a zero-length string to a non-zero-length string, finding a string which contains the proper characters is easy.
Because of behavioral details like the above, in most cases the only legitimate application of ReferenceEquals with strings is in situations where a true result is interpreted to say "the strings definitely contain the same characters" and a "false" result to say "the strings might not contain the same characters". It should not be interpreted as saying anything about where the strings came, how they were created, or anything like that.
When you concatenate with the identity (the empty string) the
reference maintains intact. Is this a compile time optimization or is
the overloaded assignment operator making the decision to not realloc
at runtime?
Neither. It's the Concat method that does that decision. The code is actually compiled into:
s1 = String.Concat(s1, "");
The Concat method contains this code, that makes it return the first parameter if the second is empty:
if (IsNullOrEmpty(str1)) {
return str0;
}
Ref: Microsoft reference source: String.Concat(string, string)
My program would indicate that the memory at the original address of
s1 remains intact (and s2 continues pointing there) while a relloc
occurs for the new value and then s1 is pointed there
That is correct.
This question already has answers here:
C# difference between == and Equals()
(20 answers)
Closed 9 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
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?
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:
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
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
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
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
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
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
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));
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:
About String.Equals method - Determines whether this instance and
another specified String object have the same value. (http://msdn.microsoft.com/en-us/library/858x0yyx.aspx)
About == - Although string is a reference type, the equality operators (== and
!=) are defined to compare the values of string objects, not
references. This makes testing for string equality more intuitive. (http://msdn.microsoft.com/en-en/library/362314fe.aspx)
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."
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.
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
I know there are a lot of ways to compare VALUE and REFERENCES in C#, but I'm still a bit confused about what type performs what when you try to compare either VALUE or REFERENCE.
String examples:
string str = "hello";
string str2 = "hello";
if (str == str2)
{
Console.WriteLine("Something");
} // Is this a comparison of value?
if (str.Equals(str2))
{
Console.WriteLine("Something");
} // Is this a comparison of value?
string.ReferenceEquals(str, str2); // Comparison of reference (True)
Console.WriteLine((object)str1 == (object)str2); // Comparison of reference (True)
Equals and == will compare by reference by default if they're not overriden / overloaded in a subclass. ReferenceEquals will always compare by reference.
Strings are a confusing data type to use for experimenting with this, because they overload == to implement value equality; also, since they're immutable, C# will generally reuse the same instance for the same literal string. In your code, str and str2 will be the same object.
#Inerdia is right with what he says but I'd like to point out the reason why the line string.ReferenceEquals(str, str2) returns true in your code example. Because you are defining both of the strings at compile time, the compiler can optimise the code so they can both point to the same instance of the string. Since strings are immutable the compiler knows it can do this even though String is a reference type. But If you change your code to dynamically generate one of the strings (as shown below) the compiler can't perform this optimisation. So in your code example if you change your code to:
string str = "hello";
string str2 = new StringBuilder().Append("he").Append("llo").ToString();
Then the string.ReferenceEquals(str, str2) line will now return false as this time the compiler cant know to re-use the same instance (reference of the string).
Equality and Comparision of ReferenceTypes and strings:
Reference types work like this:
System.Object a = new System.Object();
System.Object b = new System.Object();
a == b; //returns true
a.Equals(b); //returns false
b = a;
a == b; //returns true
a.Equals(b); //returns true
Since strings are Reference types they should do the same, shouldn't they? But they don't!
C# Documentation defines string equality like this:
Although string is a reference type, the equality operators (== and
!=) are defined to compare the values of string objects, not
references (7.9.7 String equality operators). This makes testing for
string equality more intuitive.
https://msdn.microsoft.com/en-us/library/362314fe%28v=vs.71%29.aspx
https://msdn.microsoft.com/en-us/library/aa664728%28v=vs.71%29.aspx
This has implications for you test code.
if (str == str2)
{
Console.WriteLine("Something");
} // This is comparision of value even though string is a referenceType
if (str.Equals(str2))
{
Console.WriteLine("Something");
} // This is comparison by value too, because Equals is overrided in String class.
Keep in mind you as a programmer (Or your tricky coworker) can override .Equals(), changing it's behaviour, what you see above is what should happen. It's not necessarily in line with your codebase-reality, when in doubt check out the definition by marking .Equals() and hitting F12.
Addendum for x.Equals
The behavior of object.Equals() should these rules:
List item
x.Equals(x) returns true.
x.Equals(y) returns the same value as y.Equals(x).
if (x.Equals(y) && y.Equals(z)) returns true, then x.Equals(z) returns true.
Successive invocations of x.Equals(y) return the same value as long as the objects referenced by x and y are not modified.
x.Equals(null) returns false.
https://msdn.microsoft.com/ru-ru/library/ms173147%28v=vs.80%29.aspx
Whenever you are in doubt you can call x.ReferenceEquals, it's defined as following:
Unlike the Object.Equals(Object) method and the equality operator, the
Object.ReferenceEquals(Object) method cannot be overridden. Because of
this, if you want to test two object references for equality and you
are unsure about the implementation of the Equals method, you can call
the method.
https://msdn.microsoft.com/de-de/library/system.object.referenceequals%28v=vs.110%29.aspx
Thus:
System.Object a = new System.Object();
System.Object b = a;
System.Object.ReferenceEquals(a, b); //returns true
In your example the compiler merges your strings in optimization thus:
string str = "hello";
string str2 = "hello";
string.ReferenceEquals(str, str2); // Comparison of reference (True)
This behaviour is only duo to compiler optimization in your example, if we randomize the code it will return false:
string str = "hello";
string str2 = "hello";
if(throwCoin)
{
str2 = "bye";
}
string.ReferenceEquals(str, str2); // Comparison of reference (False)
string.ReferenceEquals(str, str2);
It obviously compares references.
str.Equals(str2)
Tries to compare references at first. Then it tries to compare by value.
str == str2
Does the same as Equals.
A good way to compare strings is to use string.Compare. If you want to ignore case, there is a parameter in place for that too.
Excerpt from .net sources:
public bool Equals(string value)
{
if (this == null)
throw new NullReferenceException();
else if (value == null)
return false;
else if (object.ReferenceEquals((object) this, (object) value))
return true;
else
return string.EqualsHelper(this, value);
}
So in general it is comparision of references first and if they don't match, it compares values.
This question already has answers here:
C# difference between == and Equals()
(20 answers)
Closed 9 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
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?
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:
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
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
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
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
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
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
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));
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:
About String.Equals method - Determines whether this instance and
another specified String object have the same value. (http://msdn.microsoft.com/en-us/library/858x0yyx.aspx)
About == - Although string is a reference type, the equality operators (== and
!=) are defined to compare the values of string objects, not
references. This makes testing for string equality more intuitive. (http://msdn.microsoft.com/en-en/library/362314fe.aspx)
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."
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.
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