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

Is there a way to check if two string with same value are the same instance in C#?

提问人:Ryan Liu 提问时间:12/23/2022 最后编辑:M. JustinRyan Liu 更新时间:11/7/2023 访问量:405

问:

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

甚至将返回 true,因为它只是调用 .Object.ReferenceEquals("A", "A")==

此测试将通过。所以还在等待检查是否相同的实例。

  [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);
            }
            
        }
C# 字符串 相等

评论

0赞 David 12/23/2022
它们可能是相同的引用,如果编译器将两个相同的不可变值优化为一个,我不会感到惊讶。为什么需要区分它们?您要解决的根本问题是什么?
3赞 Phylyp 12/23/2022
字符串实习 - 等效的字符串文本将替换为对同一文本的引用。
4赞 Klaus Gütter 12/23/2022
“Object.ReferenceEquals(”A“, ”A“) 将返回 true,因为它只是调用 ==” - 不,它不会
0赞 juharr 12/23/2022
尝试Object.ReferenceEquals("A", "AB".Substring(1))

答:

9赞 Kit 12/23/2022 #1

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

现在,非文字不会被隔离,这将使你的测试失败。例如,对于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

你又回到了又回来了。ReferenceEqualstrue

简而言之,绝对有一种方法可以使用指针或通过指针检查两个字符串是否是相同的引用。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"