引用类型 - 我们可以看到实际的引用吗?
引用类型和值类型之间的差异通常会让初学者感到困惑,因为不了解值类型的变量实际上是什么。我们知道:引用类型 - 我们可以看到实际的引用吗?
- 值类型存储实际值
- 引用类型只有参考存储对象
是否可以检查每一个类型的变量,要么看该值,还是实际参考本身?参考是否存储为某种编码值?我知道引用可以通过值传递,所以我假设如此。
我认为这将有助于新人的理解,并且非常有趣的探索。
是否可以检查每种变量以查看值或实际引用本身?
只是为了澄清,引用类型的变量的值是的参考。参考是价值。
引用是一种值,就像int是一种值。与int不同,参考值只能是复制和取消引用;你不能直接在C#中观察它的值,因为它的值是垃圾收集器的实现细节。
是否将参考存储为某种编码值?
是的,正好。在实践中,一个引用是一个32或64位整数(取决于你是在一个32位还是64位的进程中),这个指针指向垃圾收集器已知的一些结构的指针,与被引用对象的数据相关联。
如果您想直接查看引用,那么执行此操作的工具就是调试器。将C#代码加载到调试器中,编译它,运行它,找到一个断点,并查看堆栈和寄存器的状态。有一点聪明,你应该能够找出哪些堆栈位置和寄存器对应于哪些局部变量。与值类型的局部变量相对应的位置将包含这些值;那些引用类型将包含看起来像指针的值。如果您检查内存窗口中的这些指针,您将查看由垃圾回收器维护的用于描述对象内容的结构。
我认为重要的是要注意,虽然现有的.net实现可能会将地址(对象信息记录的地址)存储在引用变量中,但不能保证将来的版本可以这样做。例如,有可能参考变量的某些位是选择多个堆中的一个的索引,而其他位是该堆中的索引。虽然这样的系统对于现有的处理器可能效率低下,但围绕这种模型设计未来的处理器可能允许更高效的高速缓存利用。现有的.net代码不应该关心这些细节。 – supercat 2012-01-11 17:06:55
@supercat:绝对。实际上,引用可以被实现为完全不透明的句柄,它们只是索引到垃圾收集器拥有的某个表中才有意义;没有理由为什么参考文献中的任何位需要具有特定的含义。碰巧,在今天的实现中,引用*的每一位都是有意义的,因为它可以被解释为一个指针。但是这随时都可能发生变化。 – 2012-01-11 17:12:21
出于好奇,虽然现有的CPU可能不会让这些事情变得非常有效,但我想知道在未来的CPU中,对于数据量为8(可能是16)个字节或更少的对象有一个小对象堆是否值得,对象表中的每个插槽将保存实际的对象数据,而不是指向它的指针。在现有的CPU上,每个堆访问都需要额外的指令来确定哪个堆是给定的引用所属的,但是如果有一个“获取对象地址”指令,它在引用中用一点来选择单向或双向间接... – supercat 2012-01-11 17:30:36
你可以很容易地用固定的物体做到这一点;
GCHandle gch=GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr AddressInMemory=gch.AddrOfPinnedObject();
与[几乎所有类一样,这对[不可擦]类型(http://msdn.microsoft.com/zh-cn/library/75dwhxf7.aspx)不起作用。 – svick 2012-01-11 12:39:08
我站好了。看起来像我唯一需要的是与原始人在一起。 – 2012-01-11 12:45:33
你可以用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
}
}
这使得s的固定副本,所以你为什么不直接pin s? – 2012-01-11 12:38:24
我们不会用's'来做任何事情。 – 2012-01-11 12:39:27
@EugenRieck您是否有该陈述的来源?我看不到在这里复制。 – CodesInChaos 2012-01-11 12:41:39
这可能是一个乔恩斯基特,但我可能有一个不同的角度:
不要担心如何这些东西在内存中表示。除非您已经阅读了整个语言规范 - 无论如何,谁还这样做? - 你并不需要知道。真。不要费心记忆哪些数据存储在哪里 - 很可能这是特定于实现的。
相反,用语义来思考,例如,传递给函数的值类型是复制,而引用类型是引用。像这样的东西。
你并不真正想知道一个类型的声明实际上是什么。相信我。你想知道的是它是如何表现的。
+1这里是Eric Lippert说的(http://blogs.msdn.com/b/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx)同样的东西。地址是实现细节,语言规范在指定引用时没有提及地址。了解他们的行为方式,而不是他们的工作方式。 – MarkJ 2012-01-11 12:51:31
虽然我同意你的发言,但我觉得这不是问题的关键。我想他想知道如何去做 - 而不是你的意见,为什么它不重要。了解复杂功能的运作方式可以使您成为更好的工程师,即使您没有找到即时使用该知识的工具。 – 2012-01-11 13:16:10
虽然我都非常感谢并且同意你的回答,但并没有解决我的问题。我只想访问地址**只是为了证明它在那里**没有其他原因。我同意@ AdamG.Carstensen。 – 2012-01-11 13:40:19
你只会看到一个地址,一个看似随机的数字。你为什么想看到这个? – Dykam 2012-01-11 12:24:43
巩固变量内部不是他们设定的对象的想法,而是一个地址。我们如何访问这个? – 2012-01-11 12:25:32
http://*.com/questions/1978232/how-can-i-display-the-actual-value-of-a-reference-in-c-sharp – 2012-01-11 12:33:18