3

MSDN states that

String.Intern retrieves the system's reference to the specified String

and

String.IsInterned retrieves a reference to a specified String.

I think that IsInterned should have returned (I know it doesn't) a bool stating whether the specified string is interned or not. Is that correct thinking ? I mean it is atleast not consistent with .net framework naming convention.

I wrote the following code:

    string s = "PK";
    string k = "PK";

    Console.WriteLine("s has hashcode " + s.GetHashCode());
    Console.WriteLine("k has hashcode " + k.GetHashCode());
    Console.WriteLine("PK Interned " + string.Intern("PK"));
    Console.WriteLine("PK IsInterned " + string.IsInterned("PK"));

The output is :

s has hashcode -837830672

k has hashcode -837830672

PK Interned PK

PK IsInterned PK

Why is string.IsInterned("PK") returning "PK"?

P.K
  • 18,587
  • 11
  • 45
  • 51
  • 1
    If you want to know more about the details of strings and interning please see my answer to this question http://stackoverflow.com/questions/372547/where-do-java-and-net-string-literals-reside/372559#372559 – Brian Rasmussen Sep 04 '09 at 18:47
  • 2
    The name is very booleanish. Perhaps it was a typo of "IfInterned". – Greg Sep 04 '09 at 19:30
  • Remark to your use of `GetHashCode`: Please note that the `System.String` class *overrides* `GetHashCode()`. So such a method call is not useful to check if the instances might be different. Instead include a `using System.Runtime.CompilerServices;` directive and use `RuntimeHelpers.GetHashCode(string)`. Here is a good example: `string s = "PK"; string t = 'P'.ToString() + "K"; Console.WriteLine("s has non-overridden hashcode " + RuntimeHelpers.GetHashCode(s)); Console.WriteLine("t has non-overridden hashcode " + RuntimeHelpers.GetHashCode(t));`. – Jeppe Stig Nielsen Feb 26 '15 at 13:56

1 Answers1

19

String.Intern interns the string if it's not already interned; String.IsInterned doesn't.

IsInterned("PK") is returning "PK" because it's already interned. The reason for it returning the string instead of a bool is so that you can easily get a reference to the interned string itself (which may not be the same reference as you passed in). In other words, it's effectively returning two related pieces of information at once - you can simulate it returning bool easily:

public static bool IsInternedBool(string text)
{
     return string.IsInterned(text) != null;
}

I agree that the naming isn't ideal, although I'm not sure what would have been better: GetInterned perhaps?

Here's an example showing that difference though - I'm not using string literals, to avoid them being interned beforehand:

using System;

class Test
{
    static void Main()
    {
        string first = new string(new[] {'x'});
        string second = new string(new[] {'y'});

        string.Intern(first); // Interns it
        Console.WriteLine(string.IsInterned(first) != null); // Check

        string.IsInterned(second); // Doesn't intern it
        Console.WriteLine(string.IsInterned(second) != null); // Check
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon Thanks for the answer. Is it correct to think that declaration of string s must have interned "PK". Then what will String.Intern("PK") do? – P.K Sep 04 '09 at 18:46
  • 4
    All literal strings are interned by default. – Brian Rasmussen Sep 04 '09 at 18:49
  • 1
    @PK, if the string has already been interned, then Intern will return the exact same reference that was passed in. I wasn't aware of the fact that literals are interned automatically, but it completely makes sense. – Steven Sudit Sep 04 '09 at 18:51
  • Then, how to construct a string that is *not* interned? – Dmitri Nesteruk Oct 04 '19 at 13:18
  • @DmitriNesteruk: `new String(String)`? – Jon Skeet Oct 04 '19 at 15:03
  • @JonSkeet sorry, don't get you. `new String(String)` will not compile. – Dmitri Nesteruk Oct 04 '19 at 17:20
  • @DmitriNesteruk: Whoops, hadn't checked the tags. Was looking for a `String(String)` constructor, which exists in Java. You can use `new string(text.ToCharArray())` which will always create a new string object *unless* `text` is an empty string, in which case - at least in some versions of .NET - you'll still get a reference back which refers to an existing object. – Jon Skeet Oct 04 '19 at 17:37
  • @JonSkeet but this makes even less sense! because for any given empty string, `ReferenceEquals("", string.Empty)` always returns `true`, right? I would assume the empty string to be definitely interned always. – Dmitri Nesteruk Oct 04 '19 at 17:41