Why some identical strings are not interned in .NET?

后端 未结 5 1525
悲&欢浪女
悲&欢浪女 2020-12-21 00:17
string s1 = \"test\";
string s5 = s1.Substring(0, 3)+\"t\"; 
string s6 = s1.Substring(0,4)+\"\";   
Console.WriteLine(\"{0} \", object.ReferenceEquals(s1, s5)); //Fa         


        
相关标签:
5条回答
  • 2020-12-21 00:58

    Strings in .NET can be interned. It isn't said anywhere that 2 identical strings should be the same string instance. Typically, the compiler will intern identical string literals, but this isn't true for all strings, and is certainly not true of strings created dynamically at runtime.

    0 讨论(0)
  • 2020-12-21 01:13

    The CLR doesn't intern all strings. All string literals are interned by default. The following, however:

    Console.WriteLine("{0} ", object.ReferenceEquals(s1, s6)); //True
    

    Returns true, since the line here:

    string s6 = s1.Substring(0,4)+"";  
    

    Is effectively optimized to return the same reference back. It happens to (likely) be interned, but that's coincidental. If you want to see if a string is interned, you should use String.IsInterned()

    If you want to intern strings at runtime, you can use String.Intern and store the reference, as per the MSDN documentation here: String.Intern Method (String). However, I strongly suggest you not use this method, unless you have a good reason to do so: it has performance considerations and potentially unwanted side-effects (for example, strings that have been interned cannot be garbage collected).

    0 讨论(0)
  • 2020-12-21 01:13

    The Substring method is smart enough to return the original string in the case where the substring being requested is exactly the original string. Link to the Reference Source found in comment by @DanielA.White. So s1.Substring(0,4) returns s1 when s1 is of length 4. And apparently the + operator has a similar optimization such that

    string s6 = s1.Substring(0,4)+"";
    

    is functionally equivalent to:

    string s6 = s1;
    
    0 讨论(0)
  • 2020-12-21 01:17

    You should get false for calls of ReferenceEquals on string objects that are not string literals.

    Essentially, the last line prints True by coincidence: what happens is that when you pass an empty string for string concatenation, library optimization recognizes this, and returns the original string. This has nothing to do with interning, as the same thing will happen with strings that you read from console or construct in any other way:

    var s1 = Console.ReadLine();
    var s2 = s1+"";
    var s3 = ""+s1;
    Console.WriteLine(
        "{0} {1} {2}"
    ,   object.ReferenceEquals(s1, s2)
    ,   object.ReferenceEquals(s1, s3)
    ,   object.ReferenceEquals(s2, s3)
    );
    

    The above prints

    True True True
    

    Demo.

    0 讨论(0)
  • 2020-12-21 01:17

    From msdn documentation of object.ReferenceEquals here:

    When comparing strings.If objA and objB are strings, the ReferenceEquals method returns true if the string is interned.It does not perform a test for value equality.In the following example, s1 and s2 are equal because they are two instances of a single interned string.However, s3 and s4 are not equal, because although they are have identical string values, that string is not interned.

    using System;
    
    public class Example
    {
       public static void Main()
       {
          String s1 = "String1";
          String s2 = "String1";
          Console.WriteLine("s1 = s2: {0}", Object.ReferenceEquals(s1, s2));
          Console.WriteLine("{0} interned: {1}", s1, 
                            String.IsNullOrEmpty(String.IsInterned(s1)) ? "No" : "Yes");
    
          String suffix = "A";
          String s3 = "String" + suffix;
          String s4 = "String" + suffix;
          Console.WriteLine("s3 = s4: {0}", Object.ReferenceEquals(s3, s4));
          Console.WriteLine("{0} interned: {1}", s3, 
                            String.IsNullOrEmpty(String.IsInterned(s3)) ? "No" : "Yes");
       }
    }
    // The example displays the following output:
    //       s1 = s2: True
    //       String1 interned: Yes
    //       s3 = s4: False
    //       StringA interned: No
    
    0 讨论(0)
提交回复
热议问题