分配给引用类型变量的 pointer/reference 的隐藏值是多少?

What is the hidden value of the pointer/reference assigned to reference type variables?

int number = 1

number的值为1,因为它是值类型

分配给引用类型变量的指针的实际值是多少?

是整数还是字符串?或者它是一些比特?如果你把它写出来会是什么样子?是否可以使用该值分配对变量的引用?

Question harrysQuestion = new Question();

harrysQuestion 只是对新问题的指针或引用。那么该指针的值是多少?如果我这样做,分配给另一个问题变量的相同值:

Question harrysQuestionAgain = harrysQuestion;

它是指向我计算机内存中某个位置的数字吗?它是幕后实际的 C# 值变量吗?

Is it a number that points to some position in my computers memory?

从概念上讲,引用和指针是分开但相关的。实际上,它们 virtually 可以互换,区别在于 GC 知道如何遍历和修复引用(垃圾 collection 等),但不知道指针(还有其他关于fixed 如何在值的 hack 方面工作,允许在堆栈上找到的引用 value 被廉价地解释为 "pinned")。实际上,它们在所有实现中 非常接近 each-other(出于性能原因),您可以将它们视为 kinda一样。

您实际上想要获取引用的"value"(而不是解除引用),并且除非您首先固定 object,否则您需要非常小心,因为地址可能会更改(并且指针版本 不会被更正 )。对于这个 use-case 的需求实际上 增加 即将到来的 "pipelines" 工作,因此 Unsafe 实用程序类型的 corefxlab / myget 版本实际上提供了一些促进引用/指针交换的方法(包括内部 pointers/references 到 objects),但是:除非你正在做一些低级别的事情,否则你可能永远不需要它。


每个请求(评论):我提到了 "pinning" 和 "fixed" - 这里的问题是 .NET 有一个 "compacting" 垃圾收集器,允许 在运行时将 object 移动到 附近,只要它承诺修复所有引用 确保您永远不会从托管代码中注意到这一点。它承诺的是修复指针。所以:如果您要将任何 object 视为指针 ,您需要告诉运行时(尤其是:垃圾收集器)根本不要移动 object,或者至少在您告诉它您完成之前。这就是 "pinning" 的意思。 "pin"有两种方式:

  • 用于 long-term 引脚(通常是像 byte[] 缓冲区这样的东西,您将作为字段存储在 object 中并作为指针传递给非托管代码),您可以对 object 使用 GCHandle,它会记录在 GC 知道要查看的全局结构中
  • 对于 在堆栈上 的引用的 short-term 引脚,fixed 关键字做了一些让 GC(总是查看每个stack) 知道引用 - 因此 object 被引用到 (该地址的 object ) - 应该被认为是固定的, 没有 需要不断地 add/remove 到全局结构

作为一个可能有趣的旁注:"interior references" 和对值类型的引用是一个概念 仅存在于堆栈上 - 而不是 字段 在可能最终出现在堆上的类型上(这意味着任何 classstruct 除了新的 ref struct 概念)。它们的工作方式与常规引用相同,但这些引用的目标是 内容本身 ,而不是 object header 的开头。这意味着

var fieldReference = ref this._someField;

SomeOtherMethod(ref this._someField);

SomeOtherMethod(ref someArray[index]);

在方法内部工作只要内部引用仅在堆栈上(即没有 async / yield / captured-variables / ETC); GC 乐于承担解析指向 objects 的内部指针的开销,但仅针对堆栈 - 以减少所涉及工作的总体规模。