2

I am new to C# string I am confused about the

 Object.referenceEquals 

I was reading some article which says ReferenceEquals check if it same instance or not in the program i am checking if object.ReferenceEquals(s1, s4) even though they point to same data why it is coming as false ?

string s1 = "akhil";
string s2 = "akhil";

Console.WriteLine(object.ReferenceEquals(s1, s2)); //true
s2 = "akhil jain";
Console.WriteLine(object.ReferenceEquals(s1, s2)); //false
//Console.WriteLine(s1 == s2);
//Console.WriteLine(s1.Equals(s2));

string s3 = "akhil";
//1".Substring(0, 5);
Console.WriteLine(s3+" " +s1);
Console.WriteLine(object.ReferenceEquals(s1,s3)); //true


string s4 = "akhil1".Substring(0, 5);
Console.WriteLine(object.ReferenceEquals(s1, s4)); //confusion false why as s4 data is same as s1
Deepak Jain
  • 137
  • 1
  • 3
  • 27
Deepak Jain
  • 109
  • 6
  • it returns akhil @Loocid – Deepak Jain Apr 30 '19 at 06:37
  • 3
    You have two string objects, both with the same data, but they're still separate objects - which is why `ReferenceEquals` returns false. `Substring` doesn't look all through memory to try to find other string objects with the same content. – Jon Skeet Apr 30 '19 at 06:40
  • Possible duplicate of [C# .Equals(), .ReferenceEquals() and == operator](https://stackoverflow.com/questions/3869601/c-sharp-equals-referenceequals-and-operator) – peeyush singh Apr 30 '19 at 06:42
  • by ur statement 1st object.ReferenceEquals(s1, s2) should be false then why it's true ? – Deepak Jain Apr 30 '19 at 06:42
  • It would be true when you do something like this: `string s1 = 'Test'; string s2 = s1;` – Leon Apr 30 '19 at 06:43
  • 1
    Because s1 and s2 refer to the *same* object, due to the way string literals work. Every time you use the same string literal in C# within one program, you'll end up with a reference to the same object. That's *not* the case when you call Substring. – Jon Skeet Apr 30 '19 at 06:43
  • String literals with same content are considered the same string instance as showed at the bottom of this page: [2.4.4.5 String literals](https://msdn.microsoft.com/en-us/data/aa691090(v=vs.85)) – J3soon Apr 30 '19 at 06:44
  • You can see the substring part as `s4 = new String("akhil")`, which has created another instance – J3soon Apr 30 '19 at 06:45
  • Also check the documentation , https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals?view=netframework-4.8 – Hammad Sajid Apr 30 '19 at 06:53

3 Answers3

2

The references are the same because a string literal gets interned, Substring returns a new string and a new reference, it doesn't try to second guess your parameters and check the intern pool

String.Intern(String) Method

The common language runtime conserves string storage by maintaining a table, called the intern pool, that contains a single reference to each unique literal string declared or created programmatically in your program. Consequently, an instance of a literal string with a particular value only exists once in the system.

For example, if you assign the same literal string to several variables, the runtime retrieves the same reference to the literal string from the intern pool and assigns it to each variable.

Though, useless fact 3454345.2, Since .Net 2, you have been able to turn it off for various reasons you may have

CompilationRelaxations Enum

NoStringInterning Marks an assembly as not requiring string-literal interning. In an application domain, the common language runtime creates one string object for each unique string literal, rather than making multiple copies. This behavior, called string interning, internally requires building auxiliary tables that consume memory resources.

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
0

When instantiating two object, the reference is not equal. The Object.ReferenceEquals method therefore returns false. However, strings are a very special case. If you declare a string in code, the CLR maintains it in a table. This is called the intern pool. This causes two strings that were instantiated with the same value to reference the same object in memory. This will cause Object.ReferenceEquals to return true.

When a string was formed by some operation in your code, it is not automatically interned to the pool. And therefore, it has a different reference, although the content of the string might be the same. This is also explained in the remarks of the documentation of Object.ReferenceEquals here.

Note that the String.Equals() method would return true. In C# you can also use the '==' operator on strings. See your adjusted code below.

string s1 = "akhil";
string s2 = "akhil";

Console.WriteLine(s1.Equals(s2)); //true
s2 = "akhil jain";
Console.WriteLine(s1.Equals(s2)); //false

string s3 = "akhil";
Console.WriteLine(s3 + " " + s1);
Console.WriteLine(s1.Equals(s3)); //true

string s4 = "akhil1".Substring(0, 5);
Console.WriteLine(s1.Equals(s4)); //this now returns true as well
Console.WriteLine(s1 == s4);      //so does this
Chris
  • 323
  • 2
  • 12
0

The value of object.ReferenceEquals is false since it checks if both the references point to the same object. ReferenceEquals does not check for data equality, but if both objects occupy the same memory address.

As TheGeneral already mentioned, string literals are interned and stored in a table called intern pool. This is to store string objects efficiently.

When a string literal is assigned to multiple variables, they are pointing to the same address in the intern pool. Hence, you get true for object.ReferenceEquals. But when you compare this with a substring, a new object has been created in the memory. This result in a false when reference is compared since they are two different objects occupying different memory locations.

All the dynamically created strings, or read from an external source are not interned automatically.

If you try the following, you will get true for object.ReferenceEquals:

Console.WriteLine(object.ReferenceEquals(s1, string.Intern(s4)));

You can check with Primitive data types that the ReferenceEquals returns false even when one variable is assigned to another.

int a = 10;
int b = a;
Console.WriteLine(ReferenceEquals(a, b)); //false

This is because each primitive type is stored separately.

Shakti Prakash Singh
  • 2,414
  • 5
  • 35
  • 59