Object and String Comparisons

,String Intern Pool

C# String Intern Pool

.Object and String Comparisons

"This video demonstrates and how strings and objects are stored in memory, how the string intern pool works, and the immutability of strings ."

Four code sections are animated in Visual Studio 2012 and the Output, Watch, and two Memory windows are monitored.


The Demonstration

The four code segments used in this demonstration are:

  1. Objects: Reference vs Value Comparisons

    C# is similar to Java when comparing objects. The == operator compares the addresses of the objects in the heap. So when two objects (o1 and o2) are created and each given the value of 5, the (o1 == o2) returns False. The .Equals method is used to compare the contents of the objects. The comparison o1.Equals(o2) returns True when the content of the objects are the same.

    • For C#, when comparing objects
      • The == operator performs a reference comparison.
      • The .Equals method performs a value comparison.
  2. Strings: Reference vs Value Comparisons

    However, C# is unlike Java when comparing strings in that the == operator compares the contents of strings. So when two strings (s1 and s2) are created and each given the value of 5, the (s1 == s2) returns True. The .Equals method is also used to compare the contents of the strings. The ReferenceEquals method is used to perform a reference comparison between strings, e.g. ReferenceEquals(s1, s2).

    • For C#, when comparing strings
      • The == operator performs a value comparison.
      • The .Equals method performs a value comparison.
      • The .ReferenceEquals method performs a reference comparison.
  3. String Intern Pool

    The String Intern Pool is a reference table to unique literal strings which is maintained by the Common Language Runtime. Strings are only put into the pool at compile time or when the Intern method is used. The demonstration shows that simply changing the string literal at run time to equal a literal value already stored in the pool does not cause the string to point to the interned string. For this to happen the Intern method must be used. The Intern method searches the string pool for a value equal to a specified string. If the string value is found, its reference address in the string pool is returned. If the string value is not found, the string value is added to the intern pool and that new reference address is returned.

,String Intern Pool

C# String Intern Pool

  1. Immutable Strings

    When a string literal is created at compile time the string resides in the String Intern Pool. At runtime, each time the string literal is changed, a new string containing the changed value is created in the heap. This can consume a large amount of memory when strings are changed frequently, such as inside a loop. In these situations the StringBuilder class should be used. A StringBuilder object is mutable and maintains a buffer to accommodate expansions to the string.

,Immutable Strings

C# Immutable Strings

Strings in C# and Java

The difference between Strings in C# and Java is explained in the MSDN Data Types (C# vs. Java) page as follows:

String types in both Java and C# exhibit similar behavior with slight differences. Both string types are immutable, meaning that the values of the strings cannot be changed once the strings have been created. In both instances, methods that appear to modify the actual content of a string actually create a new string to return, leaving the original string unchanged. The process of comparing string values is different in C# and Java. To compare string values in Java, developers need to call the equals method on a string type as the == operator compares reference types by default. In C#, developers can use the == or != operators to compare string values directly. Even though a string is a reference type in C#, the == and != operator will, by default, compare the string values rather then references.

Just like in Java, C# developers should not use the string type for concatenating strings to avoid the overhead of creating new string classes every time the string is concatenated. Instead, developers can use the StringBuilder class, which is functionally equivalent to the Java StringBuffer class.

C# Code Used in Demonstration Video

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObjectandStringTests
    class ObjectandStringTests
        static void Main(string[] args)
#region objects
            // For Objects: == is a reference comparison.
            // For Objects: .Equals is a value comparison.
           Console.WriteLine("O ------------------");  
            int i = 5;           
            object o1 = i, o2 = i;

            Console.WriteLine("Result is: {0}", (o1 == o2));        // False  (Reference Comparison)
            Console.WriteLine("Result is: {0}", o1.Equals(o2));    // True   (Value Comparison)
            Console.WriteLine("Result is: {0}", ReferenceEquals(o1, o2));   // False (Reference Comparison)
            Console.WriteLine("O ------------------\n");
#endregion objects

#region strings
            // For Strings: == is a value comparison.
            // For Strings: .Equals is a value comparison.
            Console.WriteLine("S ------------------");  
            string s1 = "kevin", s2 = "kevin";

            Console.WriteLine("Result is: {0}", (s1 == s2));                // True   (Value Comparison)
            Console.WriteLine("Result is: {0}", s1.Equals(s2));             // True   (Use for String Value Comparison)
            Console.WriteLine("Result is: {0}", ReferenceEquals(s1, s2));   // True ! (String Intern Pooling)
            Console.WriteLine("S ------------------\n");
#endregion strings

#region interning
            // String Intern Pooling
            Console.WriteLine("I ------------------");  
            string s3 = "kevin";
            string s4 = "kevin harris";
            string s5;

            Console.WriteLine("Result is: {0}", ReferenceEquals(s3, s4));   // False
            s3 += " harris";
            Console.WriteLine("Result is: {0}", s3.Equals(s4));             // True;
            Console.WriteLine("Result is: {0}", ReferenceEquals(s3, s4));   // False ! (Same Value, But Not Interned)
            s5 = String.Intern(s3);
            Console.WriteLine("Result is: {0}", ReferenceEquals(s5, s3));   // False !
            Console.WriteLine("Result is: {0}", (s5 == s3));                // True
            Console.WriteLine("Result is: {0}", s5.Equals(s3));             // True
            Console.WriteLine("Result is: {0}", ReferenceEquals(s5, s4));   // True !
            Console.WriteLine("I ------------------\n");
#endregion interning

#region immutable
            // Strings are immutable, they can not be changed.
            Console.WriteLine("M ------------------");  
            string s6 = "kevin";
            string s7 = "kevin";

            Console.WriteLine("Result is: {0}", ReferenceEquals(s6, s7));   // True
            s7 += "H"; // s7 is now a new string with different reference
            Console.WriteLine("Result is: {0}", ReferenceEquals(s6, s7));   // False
            Console.WriteLine("M ------------------\n");
#endregion immutable

Reference Articles