5
string s1 = "abc";
string s2 = "ab";
string s3 = s2 + "c";

Console.WriteLine(string.IsInterned(s3));           // abc
Console.WriteLine(String.ReferenceEquals(s1, s3));  // False

I just cannot understand why s3 interned, but ReferenceEquals was False.

Dose they have two copies in intern pool?

Thanks in advance.

Dirk
  • 10,668
  • 2
  • 35
  • 49
Lei Kan
  • 487
  • 7
  • 20
  • 2
    This is because while the value of that string is indeed interned (because of the literal "abc"), it is not the same instance as the interned string, rather an instance generated by the + operator – Shlomi Borovitz Mar 08 '14 at 14:36
  • 1
    @ShlomiBorovitz you should make this an answer, was going to tell that but you were faster and more precise – ppetrov Mar 08 '14 at 14:37
  • Moreover, `Console.WriteLine(String.ReferenceEquals(s1, string.IsInterned(s3)));` should return true – Shlomi Borovitz Mar 08 '14 at 14:38
  • Writing `String.ReferenceEquals` is confusing because the `static` method is in `System.Object`. So use either `ReferenceEquals` by itself (since the `class` or `struct` you are inside inherits `System.Object` ultimately) or use `object.ReferenceEquals` if you feel like emphasizing where that method is declared (or in the evil case where another user-defined `ReferenceEquals` method hides the one on `object`). – Jeppe Stig Nielsen Mar 08 '14 at 15:43

3 Answers3

6

They are separate references. The string "abc" is interned because it is a literal string.

The expression s2 + "c" is compiled to string.Concat(s2, "c").. which results in a new (and separate) string reference.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • thanks, can you tell IsInterned() more details? That's makes me confused. – Lei Kan Mar 08 '14 at 14:55
  • @LeiKan If the intern pool holds *some* string with the same *value* as `s3` then `string.IsInterned(s3)` returns the string from the intern pool. That is not necessarily the same instance as `s3`. So, as said in a comment to your question, `ReferenceEquals(s3, string.IsInterned(s3))`, or equivalently `(object)s3 == (object)string.IsInterned(s3)` can be false even when `IsInterned` does return an instance. – Jeppe Stig Nielsen Mar 08 '14 at 15:37
3

This is because while the value of that string is indeed interned (because of the literal "abc"), it is not the same instance as the interned string, rather an instance generated by the + operator.

String.ReferenceEquals(s1, string.IsInterned(s3));

would return true

Shlomi Borovitz
  • 1,700
  • 9
  • 9
  • thanks, IsInterned() makes me confused. The output "abc" tells me it was interned, but you tell me it dosen't. – Lei Kan Mar 08 '14 at 14:59
  • The [IsInterned method](http://msdn.microsoft.com/en-us/library/system.string.isinterned(v=vs.110).aspx) returns the interned **instance** for a **value** (or null, if that string is not interned). Now, while using string literal will always return an interned **instance**, other operations won't necessarily do that, even if there is an interned **instance** for that **value**. – Shlomi Borovitz Mar 08 '14 at 15:06
1

There are basically three different situations possible when string.IsInterned is invoked. To illustrate, here is a test method:

static void MyInternCheck(string str)
{
  var test = string.IsInterned(str);

  if ((object)test == (object)str)
    Console.WriteLine("Yes, your string instance is in the intern pool");
  else if (test == str)
    Console.WriteLine("An instance with the same value exists in the intern pool, but you have a different instance with that value");
  else if (test == null)
    Console.WriteLine("No instance with that value exists in the intern pool");
  else
    throw new Exception("Unexpected intern pool answer");
}

You can "hit" all three situations with this code:

static void Main()
{
  string x = "0";
  MyInternCheck(x);
  string y = (0).ToString(CultureInfo.InvariantCulture);
  MyInternCheck(y);
  string z = (1).ToString(CultureInfo.InvariantCulture);
  MyInternCheck(z);
}

Output:

Yes, your string instance is in the intern pool
An instance with the same value exists in the intern pool, but you have a different instance with that value
No instance with that value exists in the intern pool

Since the literal "0" is mentioned in the program text, a string instance with value "0" will exist in the intern pool. The variable x is a reference to that instance.

The variable y has the same value as x, but that is not computed until run-time (the C# compiler makes no guesses as to what int.ToString(IFormatProvider) could be returning). As a consequence, y is another instance than is x.

The variable z has a value that is not found in the intern pool.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181