.NET参数传递 - 按值引用v/s

Pri*_*est 17 .net c# clr value-type reference-type

我试图验证我对C#/ .NET/CLR如何处理值类型和引用类型的理解.我读过很多矛盾的解释

这就是我今天所理解的,如果我的假设是错误的,请纠正我.

诸如int等的值类型存在于堆栈上,引用类型存在于托管堆上,但是如果引用类型具有例如double类型的实例变量,则它将与其对象一起存在于堆上

第二部分是我最困惑的.

让我们考虑一个名为Person的简单类.

Person有一个名为Name的属性.

假设我在另一个类中创建了Person实例,我们称之为UselessUtilityClass.

请考虑以下代码:

class UselessUtilityClass
{
   void AppendWithUnderScore(Person p)
   {
     p.Name = p.Name + "_";
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我们在某处:

Person p = new Person();
p.Name = "Priest";
UselessUtilityClass u = new UselessUtilityClass();
u.AppendWithUnderScore(p);
Run Code Online (Sandbox Code Playgroud)

Person是一个引用类型,当传递给UselessUtilityClass时 - 这就是我去的地方 - 坚果...... 作为Person引用实例的VARIABLE p由VALUE传递,这意味着当我写p.Name时我会看到"牧师_"

如果我写的话

Person p2 = p;
Run Code Online (Sandbox Code Playgroud)

我做到了

p2.Name ="不是牧师";

写下p的名字就像下面我会得到"不是牧师"

Console.WriteLine(p.Name) // will print "Not a Priest"
Run Code Online (Sandbox Code Playgroud)

这是因为它们是引用类型并指向内存中的相同地址.

我的理解是否正确?

我认为当人们说.NET中的所有对象都通过Reference传递时会出现一些误解,这并不是基于我的想法.我错了,这就是为什么我来到堆叠器.

Eri*_*ert 27

诸如int等的值类型存在于堆栈中.引用类型存在于托管堆上,但是如果引用类型具有类型为double的实例变量,则它将与其在堆上的对象一起生存

不,这不正确.正确的语句是"在CLI的Microsoft实现中,执行线程的系统堆栈上分配的局部变量和值类型的形式参数既不直接在迭代器块中也不在λ或匿名方法的封闭外部变量中分配和Microsoft的C#实现."

不要求任何版本的C#或任何版本的CLI使用系统堆栈进行任何操作.当然我们这样做是因为它是一个方便的数据结构,用于局部变量和值类型的形式参数,它们不直接在迭代器块或lambda或匿名方法的封闭外部变量中.

请参阅我关于此主题的文章,以讨论(1)为什么这是一个实现细节,(2)我们从这个实现选择中获得了什么好处,以及(3)实现这个实现选择的愿望有哪些限制驱动到语言设计.

http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

Person是一个引用类型,当传递给UselessUtilityClass时 - 这就是我去的地方 - 坚果......

深吸一口气.

变量是存储位置.每个存储位置都有一个关联的类型.

其关联类型是引用类型的存储位置可以包含对该类型的对象的引用,或者可以包含空引用.

关联类型为值类型的存储位置始终包含该类型的对象.

变量的存储位置的内容.

作为Person引用的实例的VARIABLE p由VALUE传递,

变量p是存储位置.它包含对Person实例的引用.因此,变量的值是对Person的引用.该值 - 对实例的引用 - 传递给被调用者.现在,您混淆的另一个变量也称为"p",它包含相同的值 - 该值是对特定对象的引用.

现在,也可以传递对变量的引用,许多人发现这个变量令人困惑.当你说时,更好的思考方式就是这样

void Foo(ref int x) { x = 10; }
...
int p = 3456;
Foo(ref p);
Run Code Online (Sandbox Code Playgroud)

这意味着"x是变量p的别名".也就是说,X和P是两个名称同一个变量.因此无论p的值是什么,这也是x的值,因为它们是同一存储位置的两个名称.

现在有道理吗?


Guf*_*ffa 8

诸如int等的值类型存在于堆栈上,引用类型存在于托管堆上,但是如果引用类型具有例如double类型的实例变量,则它将与其对象一起存在于堆上

正确.

您还可以将其描述为实例变量,它们是为堆上实例分配的内存区域的一部分.

作为Person引用的实例的VARIABLE p由VALUE传递

该变量实际上不是该类的实例.该变量是对类实例的引用.引用按值传递,这意味着您传递引用的副本.此副本仍指向与原始引用相同的实例.

当人们说.NET中的所有对象都通过Reference传递时,我认为会有一些误解

是的,这绝对是一种误解.所有参数都按值传递(除非您使用refout关键字通过引用传递它们).传递引用通过引用传递不同.

引用是值类型,这意味着您作为参数传递的所有内容都是值类型.你永远不会传递一个对象实例,总是它的引用.