从我现在所理解的,我可以说C#中的引用是一种指向具有引用计数并了解类型兼容性的对象的指针。我的问题不是关于值类型如何与引用类型不同,而是关于如何实现引用的更多信息。
我已经阅读了this post关于引用和指针之间存在的差异,但这并没有涵盖引用 的内容,但是它描述了更多它&# 39; s属性与C ++中的指针进行比较。我也理解传递引用传递值之间的差异(因为在C#对象默认情况下通过值传递,甚至引用),但是当我试图向我解释时,我很难理解什么是真正的引用。同事为什么通过引用发送的参数不能像在Eric Lippert blog entry中那样存储在封闭内部,作为实现细节。
有人可以向我提供一个完整的,但希望简单的解释,说明C#中的参考资料是什么,还有一些关于它们是如何实现的?
编辑:这不是重复的,因为在Reference type in C#中解释了参考如何工作以及它与值的不同之处,但我要问的是如何在低级别定义参考
答案 0 :(得分:6)
从我现在的理解,我可以说C#中的引用是一种指向对象的指针
如果是"那种"你的意思是"在概念上类似于",是的。如果你的意思是"可以由"实施,是的。如果你的意思是" 与#34;有是的关系,就像"字符串是一种对象"那就不要。 C#类型系统在引用类型和指针类型之间没有子类型关系。
有引用计数
CLR的实现允许使用引用计数语义但不是必需这样做,而且大部分都没有。
并了解类型兼容性。
我不确定这意味着什么。物体知道自己的实际类型。引用具有静态类型,该类型与可验证代码中的实际类型兼容。运行时验证程序在分析IL时实现兼容性检查。
我的问题不在于价值类型与a的不同 引用类型,但更多关于如何实现引用。
如何实现引用是一个实现细节,这并不奇怪。
有人可以向我提供一个完整的,但希望简单的解释,说明C#中真正有哪些参考文献
引用作为引用的内容被指定为由C#语言规范操作。那就是:
我可能错过了一些规则,但这可以解决这个问题。 引用是任何行为类似于引用的内容。那是你应该关注的。引用是一种有用的抽象,因为它们是一种抽象,它使对象身份独立于对象值。
以及它们如何实施?
实际上,C#中的引用类型对象是作为内存块实现的,它以包含有关对象的信息的小头开始,并且引用被实现为指向该块的指针。由于我们有一个多代标记和扫描压实收集器,这个简单的方案变得更加复杂;它必须以某种方式知道引用图,以便在压缩堆时可以在内存中移动对象,而不会丢失引用标识的跟踪。
作为练习,您可以考虑如何实施此类计划。它构建角色以试图弄清楚如何构建一个系统,其中引用是指针和对象可以在内存中移动。你会怎么做?
当我试图向同事解释为什么通过引用发送的参数无法存储在闭包中时,我很难理解什么是真正的参考
这很棘手。重要的是要理解,在概念上,对变量的引用 - C#中的ref
参数 - 以及对引用类型的引用的引用是在概念上相似但实际上是不同的东西。
在C#中,您可以将对变量的引用视为别名。也就是说,当你说
时void M()
{
int x = 123;
N(ref x);
}
void N(ref int y)
{
y = 456;
基本上我们所说的是x
和y
是同一个变量的不同名称。 ref
是一种不幸的语法选择,因为它强调了实现细节 - 在幕后,y
是一个特殊的"变量" type - 而不是操作的语义,逻辑上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
}
你可以用引用的方式:
static bool EqualReferences(object x, object y)
{
return x == y;
}
在幕后,对变量的引用和对象的引用都是通过指针实现的。不同之处在于对变量的引用可能引用短期存储池上的变量(也就是"堆栈"),而对对象的引用是指向堆分配的对象头的指针。这就是为什么CLR限制您将变量的引用存储到长期存储中的原因;它不知道你是否会长期提及即将死去的事情。
了解如何将两种引用实现为指针的最佳方法是从C#类型系统逐步降级到作为其基础的CLI类型系统。 CLI规范的第8章应该是有趣的阅读材料;它描述了不同类型的托管指针以及每个托管指针的用途。
答案 1 :(得分:0)
C#中的引用与C ++引用非常相似。是的,确实,在下面有垃圾收集魔法正在进行,但我会说这是如何工作是一个不同的和更大的主题。
C#引用类似于C ++引用/不可变指针:没有指针算术等 - 但你可以重新分配它们(感谢Ben!)。
我在实践中说,一个不同之处在于,由于指针在C#中通常不可用(不安全关键字及其关联指针又是一个不同且更大的主题),你会发现自己使用“out”关键字来做什么指针到指针。
在断言引用进位类型信息时也是正确的。 C#中的所有引用都来自Object类,它本身具有GetType()方法。
但是,请注意,结构 - 通常被视为值,而不是引用 - 也具有GetType()。