有没有办法检查两个具有相同值的字符串是否是 C# 中的同一实例?

Rya*_*Liu 0 c# string equality

C# 中的 String 是一种引用类型,但它重写了==, 和Equals()来比较字符串的值。有没有办法检查两个字符串是否确实是同一实例并指向同一内存?

EvenObject.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);
            }
            
        }
Run Code Online (Sandbox Code Playgroud)

Kit*_*Kit 9

您的测试通过了,因为字符串文字会自动保留,这意味着它们共享相同的内存。因为它们共享相同的内存,所以每种形式的相等都会返回true: ReferenceEqualsEquals、通过指针固定和比较,以及==

现在,非文字不会被拘留,这将使您的测试失败ReferenceEquals。例如,对于

var a = Console.ReadLine(); // assume user enters cat
var b = Console.ReadLine(); // assume user enters cat
Run Code Online (Sandbox Code Playgroud)

ReferenceEquals将返回false。但如果你把代码改成

var a = string.Intern(Console.ReadLine()); // assume user enters cat
var b = string.Intern(Console.ReadLine()); // assume user enters cat
Run Code Online (Sandbox Code Playgroud)

你又回来ReferenceEqualstrue

简而言之,绝对有一种方法可以使用ReferenceEquals或通过指针检查两个字符串是否是同一引用。

顺便说一句,如果您保留其中一个输入,并不意味着另一个输入也被保留,除非您同时调用Intern这两个输入。当您可能使用许多基于读取控制台/文件输入、从数据库读取或以其他方式计算而可能具有相同值的字符串时,显式驻留对于减少内存非常有用。

此外,string.IsInterned在某些有限的场景中也很有用,例如,可以用于检测字符串是否由于某种原因而没有在您期望的情况下被保留。

最后,这里有一些有趣的插图。考虑

var c = "cat";
var d = new string("cat");
var e = c;
Run Code Online (Sandbox Code Playgroud)

然后这些断言,

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"
Run Code Online (Sandbox Code Playgroud)