C#中的引用到底是什么

meJ*_*rew 0 c# pointers reference

从我现在所理解的,我可以说C#中的引用是一种指向具有引用计数的对象的指针,并且知道类型兼容性.我的问题不是关于值类型如何与引用类型不同,而是关于如何实现引用的更多信息.

我已经阅读了这篇文章,介绍了引用和指针之间的差异,但这并没有涵盖引用的内容,但是它与C++中的指针相比,它描述了更多的属性.我也理解传递引用传递值之间的差异(因为C#对象默认按值传递,甚至是引用),但是当我试图向我解释时,我很难理解什么是真正的引用.同事为什么通过引用发送的参数不能存储在闭包内,如Eric Lippert 博客条目中关于堆栈作为实现细节.

有人可以向我提供一个完整的,但希望简单的解释,说明C#中的引用是什么,还有一些关于它们是如何被赋予的?

编辑:这不是重复,因为在C#中的Reference类型中,它解释了引用如何工作以及它与值的不同之处,但我要问的是如何在低级别定义引用.

Eri*_*ert 6

从我现在所理解的,我可以说C#中的引用是一种指向对象的指针

如果用"种类"表示"在概念上与"相似,是的.如果你的意思是"可以实施",是的.如果你的意思是"有一种关系",就像"一个字符串是一种对象"那么没有.C#类型系统在引用类型和指针类型之间没有子类型关系.

哪个有参考计数

允许 CLR的实现使用引用计数语义,但不要求这样做,大多数情况下不需要.

并了解类型兼容性.

我不确定这意味着什么.物体知道自己的实际类型.引用具有静态类型,该类型与可验证代码中的实际类型兼容.在分析IL时,运行时的验证程序将执行兼容性检查.

我的问题不是关于值类型如何与引用类型不同,而是关于如何实现引用的更多信息.

毫无疑问,如何实现引用是一个实现细节.

有人可以向我提供一个完整的,但希望简单的解释,说明C#中的引用是什么

引用是作为引用被指定为由C#语言规范操作的事物.那是:

  • 对象(引用类型)具有独立于其字段值的标识
  • 任何对象都可以引用
  • 这样的参考是一个,其可以被绕过像任何其他值
  • 对这些值实施了等式比较
  • 当且仅当它们引用同一个对象时,两个引用是相等的; 也就是说,引用会重新定义对象标识
  • 有一个唯一的空引用,它引用没有对象,并且不等于对象的任何有效引用
  • 静态类型总是已知的任何参考值,包括空引用
  • 如果引用为非null,则引用的静态类型始终与引用的实际类型兼容.因此,例如,如果我们有一个字符串的引用,引用的静态类型可以是字符串或对象或IEnumerable,但它不能是长颈鹿.(显然,如果引用为null,则没有指定类型的引用.)

可能有一些我错过的规则,但这可以解决这个问题.引用是任何行为都像引用的东西.这就是你应该专注的.引用是一种有用的抽象,因为它们是使对象标识独立于对象值的抽象.

还有一点关于它们是如何实现的?

在实践中,C#中引用类型的对象被实现为内存块,其以包含关于对象的信息的小头开始,并且引用被实现为指向该块的指针.由于我们有一个多代标记和扫描压实收集器,这个简单的方案变得更加复杂; 它必须以某种方式知道引用的图形,以便它可以在压缩堆时在内存中移动对象,而不会丢失引用标识的跟踪.

作为练习,您可以考虑如何实施此类计划.它构建角色以试图弄清楚如何构建一个系统,其中引用是指针,对象可以在内存中移动.你会怎么做?

当我试图向同事解释为什么通过引用发送的参数不能存储在闭包内时,我很难理解什么是真正的参考

这很棘手.重要的是要理解,从概念上讲,对变量引用ref --C#中的参数 - 以及对引用类型对象的引用在概念上是相似的,但实际上是不同的东西.

在C#中,您可以将对变量的引用视为别名.也就是说,当你说

void M() 
{
  int x = 123;
  N(ref x);
}
void N(ref int y)
{ 
    y = 456;
Run Code Online (Sandbox Code Playgroud)

从本质上讲就是我们要说的是,xy是同一个变量不同的名称.这ref是一个不幸的语法选择,因为它强调实现细节 - 在幕后,y是一个特殊的"变量"类型的引用 - 而不是操作的语义,这在逻辑上y现在只是另一个名称x; 我们有两个同名变量的名字.

对变量的引用和对象的引用在C#中不是一回事; 你可以看到这一点,因为它们有不同的语义.您可以比较两个对象的引用是否相等.但是C#中没有办法说:

static bool EqualAliases(ref int y, ref int z)
{
  return true iff y and z are both aliases for the same variable
}
Run Code Online (Sandbox Code Playgroud)

你可以用引用的方式:

static bool EqualReferences(object x, object y)
{
  return x == y;
}
Run Code Online (Sandbox Code Playgroud)

在幕后,对变量的引用和对象的引用都是通过指针实现的.不同之处在于对变量的引用可能引用短期存储池(也称为"堆栈")上的变量,而对对象的引用是指向堆分配的对象头的指针.这就是CLR限制您将变量的引用存储到长期存储中的原因; 它不知道你是否长期提及即将死亡的事情.

理解两种引用如何作为指针实现的最好方法是从C#类型系统逐步降级到作为其基础的CLI类型系统.CLI规范的第8章应该是有趣的阅读材料; 它描述了不同类型的托管指针以及每个托管指针的用途.