C#中如何查看字符串对象地址及变量地址差异原因?
问题解答
为什么word1和word2的变量地址不同,但object.ReferenceEquals返回true?
你混淆了变量的地址和变量指向的对象的地址:
&word1获取的是局部变量word1本身在栈上的存储地址,word1和word2是两个独立的局部变量,栈上的存储位置自然不同,所以输出的addr1和addr2不一样。object.ReferenceEquals(a, b)判断的是两个变量指向的是否是同一个堆对象。因为C#对字符串常量有**字符串驻留(String Interning)**优化:编译时会把相同的字符串常量存入字符串常量池,运行时多个指向该常量的变量会复用同一个堆对象,所以word1和word2的引用指向同一个"Hello"对象,ReferenceEquals返回true。
如何查看字符串对象本身的地址?
有两种常用方法,根据是否允许unsafe代码选择:
方法1:使用unsafe代码直接获取对象地址
通过Unsafe.AsPointer获取变量存储的对象引用(即堆对象地址),不需要取变量本身的地址:
using System; using System.Runtime.CompilerServices; unsafe void Method() { string word1 = "Hello"; string word2 = "Hello"; // 获取变量指向的字符串对象的堆地址 ulong objAddr1 = (ulong)Unsafe.AsPointer(ref word1); ulong objAddr2 = (ulong)Unsafe.AsPointer(ref word2); Console.WriteLine($"word1指向的对象地址:{objAddr1}"); Console.WriteLine($"word2指向的对象地址:{objAddr2}"); // 会和objAddr1相同 }
方法2:使用GCHandle(无需unsafe代码)
通过GCHandle固定对象并获取其地址:
using System; using System.Runtime.InteropServices; void Method() { string word1 = "Hello"; string word2 = "Hello"; // 获取word1指向的对象地址 GCHandle handle1 = GCHandle.Alloc(word1, GCHandleType.Pinned); IntPtr addr1 = handle1.AddrOfPinnedObject(); Console.WriteLine($"word1指向的对象地址:{addr1}"); handle1.Free(); // 获取word2指向的对象地址 GCHandle handle2 = GCHandle.Alloc(word2, GCHandleType.Pinned); IntPtr addr2 = handle2.AddrOfPinnedObject(); Console.WriteLine($"word2指向的对象地址:{addr2}"); // 会和addr1相同 handle2.Free(); }
补充说明:你代码里object.ReferenceEquals(aaa, bbb)返回false,是因为int是值类型,调用ReferenceEquals时会把它们分别装箱成两个独立的object对象,所以引用不相等。
内容的提问来源于stack exchange,提问作者UZBsdkbr
相关产品推荐
相关产品推荐

