C#中的引用到底是什么 [英] What exactly is a reference in C#

查看:116
本文介绍了C#中的引用到底是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我目前的了解,我可以说C#中的引用是一种指向具有引用计数并知道类型兼容性的对象的指针.我的问题不是关于值类型与引用类型如何不同,而是关于如何实现引用.

From what I understand by now, I can say that a reference in C# is a kind of pointer to an object which has reference count and knows about the type compatibility. My question is not about how a value type is different than a reference type, but more about how a reference is implemented.

我已阅读这篇文章,但是关于引用的内容并没有涵盖太多,但是与C ++中的指针相比,它更能描述其属性.我也了解按引用传递和按值传递之间的区别(因为在C#对象中默认情况下按值传递,甚至是引用),但是当我尝试向我的解释时,很难理解什么是真正的引用同事为什么按引用发送的参数不能像Eric Lippert那样存储在闭包中

I have read this post about what differences are between references and pointers, but that does not cover that much about what a reference is but it it's describing more it's properties compared with a pointer in C++. I also understand the differences between passing by reference an passing by value (as in C# objects are by default passed by value, even references), but it is hard for me to understand what really is a reference when I have tried to explain to my colleagues why a parameter sent by reference can not be stored inside a closure as in the Eric Lippert blog entry about the stack as an implementation detail.

有人可以为我提供有关C#中实际上是什么引用以及它们如何实现的一些完整而又希望简单的解释吗?

Can somebody provide me with a complete, but hopefully simple explanation about what references really are in C# and a bit about how they are imlemented?

这不是重复的,因为在 C#中的引用类型它解释了引用的工作原理以及它与值的区别,但是我要问的是如何在较低的级别定义引用.

this is not a duplicate, because in the Reference type in C# it is explained how a reference works and how is it different of a value, but what am I asking is how a reference is defined at a low level.

推荐答案

据我目前的了解,我可以说C#中的引用是一种指向对象的指针

From what I understand by now, I can say that a reference in C# is a kind of pointer to an object

如果用种类"来表示在概念上类似于",是的.如果您的意思是可以由...实施",则可以.如果您的意思是与之具有是一种关系",例如字符串是一种对象",则否.C#类型系统在引用类型和指针类型之间没有子类型关系.

If by "kind of" you mean "is conceptually similar to", yes. If you mean "could be implemented by", yes. If you mean "has the is-a-kind-of relationship to", as in "a string is a kind of object" then no. The C# type system does not have a subtyping relationship between reference types and pointer types.

具有引用计数

允许 使用CLR的引用,但不是必需的引用,大部分都不需要.

Implementations of the CLR are permitted to use reference counting semantics but are not required to do so, and most do not.

并了解类型兼容性.

and knows about the type compatibility.

我不确定这是什么意思.对象知道它们自己的实际类型.引用具有静态类型,该类型与可验证代码中的实际类型兼容.在分析IL时,兼容性检查是由运行时的验证程序实现的.

I'm not sure what this means. Objects know their own actual type. References have a static type which is compatible with the actual type in verifiable code. Compatibility checking is implemented by the runtime's verifier when the IL is analyzed.

我的问题不是关于值类型与引用类型,但更多关于引用的实现方式.

My question is not about how a value type is different than a reference type, but more about how a reference is implemented.

引用的实现方式并不奇怪,这是实现细节.

How references are implemented is, not surprisingly, an implementation detail.

有人可以为我提供有关C#中真正包含哪些引用的完整但希望简单的解释

Can somebody provide me with a complete, but hopefully simple explanation about what references really are in C#

引用是由C#语言规范指定用作引用的内容.那就是:

  • (引用类型的)对象具有 identity (独立于其字段值)
  • 任何对象都可能对其具有引用
  • 这样的引用是一个 value ,它可以像其他任何值一样被传递
  • 为这些值实施了
  • 平等比较
  • 两个引用在且仅当它们引用同一对象时才相等;也就是说,引用可以验证对象身份
  • 有一个唯一的空引用,它不引用任何对象,并且不等于对对象的任何有效引用.
  • 对于任何引用值,静态类型始终是已知的,包括空引用
  • 如果引用为非null,则引用的静态类型始终与引用的实际类型兼容.因此,例如,如果我们有对字符串的引用,则引用的静态类型可以是字符串或对象或IEnumerable,但不能是Giraffe.(显然,如果引用为null,则没有引用具有类型.)
  • objects (of reference type) have identity independent from the values of their fields
  • any object may have a reference to it
  • such a reference is a value which may be passed around like any other value
  • equality comparison is implemented for those values
  • two references are equal if and only if they refer to the same object; that is, references reify object identity
  • there is a unique null reference which refers to no object and is unequal to any valid reference to an object
  • A static type is always known for any reference value, including the null reference
  • If the reference is non-null then the static type of the reference is always compatible with the actual type of the referent. So for example, if we have a reference to a string, the static type of the reference could be string or object or IEnumerable, but it cannot be Giraffe. (Obviously if the reference is null then there is no referent to have a type.)

我可能遗漏了一些规则,但这贯穿了整个想法.引用是指行为类似于引用的任何内容.这就是您应该集中精力的地方.引用是一种有用的抽象,因为它们是使对象身份独立于对象值的抽象.

There are probably a few rules that I've missed, but that gets across the idea. References are anything that behaves like a reference. That's what you should be concentrating on. References are a useful abstraction because they are the abstraction which enables object identity independent of object value.

以及有关其实现方式的一些信息?

and a bit about how they are implemented?

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

In practice, objects of reference type in C# are implemented as blocks of memory which begin with a small header that contains information about the object, and references are implemented as pointers to that block. This simple scheme is then made more complicated by the fact that we have a multigenerational mark-and-sweep compacting collector; it must somehow know the graph of references so that it can move objects around in memory when compacting the heap, without losing track of referential identity.

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

As an exercise you might consider how you would implement such a scheme. It builds character to try to figure out how you would build a system where references are pointers and objects can move in memory. How would you do it?

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

it is hard for me to understand what really is a reference when I have tried to explain to my colleagues why a parameter sent by reference can not be stored inside a closure

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

This is tricky. It is important to understand that conceptually, a reference to a variable -- a ref parameter in C# -- and a reference to an object of reference type are conceptually similar but actually different things.

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

In C# you can think of a reference to a variable as an alias. That is, when you say

void M() 
{
  int x = 123;
  N(ref x);
}
void N(ref int y)
{ 
    y = 456;

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

Essentially what we are saying is that x and y are different names for the same variable. The ref is an unfortunate choice of syntax because it emphasizes the implementation detail -- that behind the scenes, y is a special "reference to variable" type -- and not the semantics of the operation, which is that logically y is now just another name for x; we have two names for the same variable.

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

References to variables and references to objects are not the same thing in C#; you can see this in the fact that they have different semantics. You can compare two references to objects for equality. But there is no way in C# to say:

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限制您将对变量的引用存储到长期存储中的原因.它不知道您是否一直在长期参考那些将很快消失的东西.

Behind the scenes both references to variables and references to objects are implemented by pointers. The difference is that a reference to a variable might refer to a variable on the short-term storage pool (aka "the stack"), whereas a reference to an object is a pointer to the heap-allocated object header. That's why the CLR restricts you from storing a reference to a variable into long-term storage; it does not know if you are keeping a long-term reference to something that will be dead soon.

理解这两种引用如何实现为指针的最佳选择是从C#类型系统过渡到作为其基础的CLI类型系统.CLI规范的第8章应该证明有趣.它描述了不同类型的托管指针以及它们的用途.

Your best bet to understand how both kinds of references are implemented as pointers is to take a step down from the C# type system into the CLI type system which underlies it. Chapter 8 of the CLI specification should prove interesting reading; it describes different kinds of managed pointers and what each is used for.

这篇关于C#中的引用到底是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆