Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String Comparision : Why we have different output for below cases

Tags:

string

c#

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 !?
like image 783
Bhuwan Pandey Avatar asked Feb 10 '23 19:02

Bhuwan Pandey


2 Answers

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");

like image 61
Matthew Watson Avatar answered Feb 12 '23 08:02

Matthew Watson


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.

like image 28
Der Kommissar Avatar answered Feb 12 '23 08:02

Der Kommissar