引用类型和值类型之间的差异通常会让初学者感到困惑,因为不了解值类型的变量实际上是什么。我们知道:
是否可以检查每种变量以查看值,还是实际参考本身?引用是否存储为某种编码值?我知道引用可以通过值传递,所以我假设是这样。
我认为这有助于新人了解他们,并且非常有趣地探索。
答案 0 :(得分:10)
是否可以检查每种变量以查看值或实际参考本身?
为了澄清,参考类型 的变量的值是引用。引用是值。
引用是一种值,就像int是一种值一样。与int不同,引用是一个只能复制和解除引用的值;您无法直接在C#中观察其值,因为它的值是垃圾收集器的实现细节。
引用是否存储为某种编码值?
是的,确切地说。实际上,引用是32位或64位整数(取决于您是在32位还是64位进程中),它是指向垃圾收集器已知的某些结构的指针,该结构与引用对象的数据相关联
如果您想直接查看引用,那么执行此操作的工具就是调试器。将C#代码加载到调试器中,编译它,运行它,命中断点,然后查看堆栈状态和寄存器。稍微聪明一点,您应该能够找出哪些堆栈位置和寄存器对应于哪些局部变量。与值类型的局部变量对应的位置将包含值;那些引用类型将包含看起来像指针的值。如果在内存窗口中检查这些指针,那么您将查看由垃圾收集器维护的描述对象内容的结构。
答案 1 :(得分:5)
这可能是Jon Skeet的一个,但我可能会有不同的角度:
不要担心过多关于 这些内容在内存中的表示方式。除非你已经阅读了整个语言规范 - 无论如何谁都这样做? - 你真的不需要知道。真。不要忘记记住哪些数据存储在哪里 - 这可能是特定于实现的。
相反,请考虑语义,例如:传递给函数的值类型是复制,而引用类型是引用。这样的东西。
你真的不想知道类型的声明实际上是什么。相信我。你想知道的是它的行为方式。
答案 2 :(得分:1)
您可以非常轻松地使用固定对象执行此操作;
GCHandle gch=GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr AddressInMemory=gch.AddrOfPinnedObject();
答案 3 :(得分:1)
您可以使用unsafe
代码执行此操作:
unsafe
static void Main(string[] args)
{
string s = "Hello";
fixed (char* pc = s)
{
IntPtr p = (IntPtr)pc;
Console.WriteLine(p); // here is your meaningless address
}
}