简体   繁体   中英

Can two identical strings be two separate instances in C#?

In C#, strings are interned. That is, if I create the string foobar and use it a second time, C# will only have one instance of the string in memory and although I will have two references, they both will be pointing to the very same string instance. This is one reason why strings are and have to be immutable in C#.

Now, my question is, whether it is possible to somehow create two identical strings so that they are not being interned, but that we end up with two different string instances in memory, with two different addresses, that contain the very same text?

If so, how?

And, is this something than can happen accidentally, or do you need to construct a scenario explicitly for this case?

And, finally: Supposed there are two separate string instances in memory with the same value, are they equal (in terms of == )? If so, how does == work? First compare by reference, then by value, or…?

In C#, strings are interned.

No. In C# strings are permitted to be interned . That is a very different statement.

That is, if I create the string foobar and use it a second time, C# will only have one instance of the string in memory and although I will have two references, they both will be pointing to the very same string instance

No. Again, in C# the runtime is permitted to decide that one "foobar" is the same as another and intern them, but it is not required to do so.

Of course, if you copy a reference then the reference is copied. But if you create a second string that looks the same as an earlier string, there is no requirement that it be interned.

In practice, strings are interned when they are literals:

string x = "foobar";
string y = "foobar";
// x is reference equal to y

or when they could be computed to be identical by the compiler:

string x = "foobar";
string y = "foo" + "bar";
// x is reference equal to y

Or when you explicitly tell the runtime that you want to intern a particular string. Otherwise strings are not typically interned:

string x = "foobar";
string y = "f" + x.Substring(1); 
// x and y are not reference equal

Only string literals are interned. Run-time interning is expensive, so dynamically created strings are not interned (unless you intern them explicitly by calling String.Intern ).

The following strings all are different instances (you can check it using object.ReferenceEquals() ):

string str1 = "foo";
string str2 = "FOO".ToLower();
string str3 = new StringBuilder().Append("f").Append("oo").ToString();

The == operator is overloaded for string to compare them by value, not by reference

public static bool operator == (String a, String b) 
{
   return String.Equals(a, b);
}

When using the == operator, you have to remember that operators are not polymorphic. So if the compile-time type of both operands is string , the string overload will be used. If at least one of them is object , the reference comparison will be performed

string str1 = "foo";
string str2 = "FOO".ToLower();
object str3 = str2;
bool valueComparison = str1 == str2;     // true - the same value
bool referenceComparison = str1 == str3; // false - different instances

Here is a very simple test proving that 2 equivalent strings don't always point to the same object reference:

static void Main(string[] args)
{
    string str1 = "foo";
    string str2 = "f";
    str2 += "oo";
    Console.WriteLine(str1 == str2); // prints true (value equality check)
    Console.WriteLine(object.ReferenceEquals(str1, str2)); // prints false (reference equality check)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM