Reputation: 55
String in C# is a reference type, but it has overridden ==
, and Equals()
to compare the value of strings. Is there a way to check if two strings are indeed the same instance and point to the same memory?
Even Object.ReferenceEquals("A", "A")
will return true since it just calls ==
.
This test will pass. So still waiting to check if the same instance.
[Test]
public void TestString()
{
var a = "A";
var b = "A";
var c = a;
Assert.IsTrue((object)a == (object)b);
Assert.IsTrue(ReferenceEquals(a,b)); //It is same as objA == objB
Assert.IsTrue(Object.ReferenceEquals(a,b));
Assert.AreEqual(a,b);
Assert.AreSame(a, b);
unsafe
{
TypedReference tra = __makeref(a);
IntPtr ptra = (IntPtr)(&tra);
TypedReference trb = __makeref(b);
IntPtr ptrb = (IntPtr)(&trb);
Assert.AreNotEqual(ptra, ptrb);
Assert.AreNotSame(ptra, ptrb);
TypedReference trc = __makeref(c);
IntPtr ptrc = (IntPtr)(&trc);
Assert.AreNotEqual(ptra, ptrc);
Assert.AreNotSame(ptra, ptrc);
Assert.IsFalse(ptra == ptrc);
}
}
Upvotes: 0
Views: 734
Reputation: 21709
Your test passes because string literals are automatically interned, meaning they share the same memory. Because they share the same memory, every form of equality is going to return true
: ReferenceEquals
, Equals
, pinning and comparison through a pointer, and ==
.
Now, non-literals are not interned, which would make your test fails for ReferenceEquals
. For example, for
var a = Console.ReadLine(); // assume user enters cat
var b = Console.ReadLine(); // assume user enters cat
ReferenceEquals
will return false
. But if you change the code to
var a = string.Intern(Console.ReadLine()); // assume user enters cat
var b = string.Intern(Console.ReadLine()); // assume user enters cat
you're right back to having ReferenceEquals
returning true
again.
In short, there is most definitely a way to check whether two strings are the same reference using ReferenceEquals
or via pointer.
Incidentally, if you interned one of the inputs, that does not imply the other input is also interned, unless you call Intern
on both. Interning explicitly is useful for reducing memory when you're likely to work with many strings that are likely to be the same value based on reading console/file input, reading from a database, or otherwise calculating.
Also, string.IsInterned can be useful in some limited scenarios, e.g. maybe for detecting if a string is not interned for some reason when you expected it to be.
Finally, here are a couple of interesting illustrations. Consider
var c = "cat";
var d = new string("cat");
var e = c;
and then these assertions,
Assert.IsTrue(ReferenceEquals(c,d)); // fails, c is interned, d is not
Assert.IsTrue(ReferenceEquals(c,e)); // succeeds, both c and e reference interned "cat"
Upvotes: 9