String在c#中是一个引用类型,但是它已经覆盖了==
和Equals()
来比较字符串的值。是否有一种方法来检查两个字符串是否确实是相同的实例,并指向相同的内存?
即使Object.ReferenceEquals("A", "A")
也会返回true,因为它只调用==
。
此测试将通过。所以仍然在等待检查是否相同的实例。
[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);
}
}
您的测试通过了,因为字符串字面值被自动存储,这意味着它们共享相同的内存。因为它们共享相同的内存,所以每一种形式的相等都将返回true
、ReferenceEquals
、Equals
,通过指针进行固定和比较,以及==
。
现在,非字面量没有被拘禁,这将使您的ReferenceEquals
测试失败。例如,对于
var a = Console.ReadLine(); // assume user enters cat
var b = Console.ReadLine(); // assume user enters cat
ReferenceEquals
将返回false
。但是如果你把代码改成
var a = string.Intern(Console.ReadLine()); // assume user enters cat
var b = string.Intern(Console.ReadLine()); // assume user enters cat
你又回到了ReferenceEquals
返回true
的状态。
简而言之,肯定有一种方法可以使用ReferenceEquals
或通过指针来检查两个字符串是否为相同的引用。
顺便说一下,如果您截取了其中一个输入,这并不意味着另一个输入也被截取了,除非您对两个输入都调用了Intern
。当您可能要处理许多字符串时,显式实习对于减少内存非常有用,这些字符串可能基于读取控制台/文件输入、从数据库读取或以其他方式计算而具有相同的值。
同时,字符串。IsInterned在一些有限的情况下是有用的,例如,可能用于检测字符串是否因为某些原因没有被拘禁,而你期望它被拘禁。
最后,这里有几个有趣的插图。考虑
var c = "cat";
var d = new string("cat");
var e = c;
然后这些断言,
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"