在阅读本文之前,你需要了解以下这几个术语是不同的:值、引用、值类型、引用类型。
注意,上面我说的都是值类型表达式和引用类型表达式,包括局部变量和成员(如字段、属性、索引器)等。现在,我们来考虑以下问题:
对于上面这些问题,您的答案是什么呢?
在谈到值类型和引用类型的区别时,很多初学者常说值类型分配在方法的调用栈(或线程栈)上,引用类型分配在托管堆上,这种说法是错误的,至少前半部分是错误的。实际上这根本不应该成为值类型和引用类型区别的答案,这是所答非所问。值类型和引用类型的区别在语义层面,与存储位置无关,并不是值类型和引用类型不同的分配方式导致了它们行为上的差异,而是因为值和引用这两种类型在语义上的差异,才导致了他们不同的分配方式。本文只讨论存储位置,不会深入介绍它们的区别。
有些朋友可能会说,详细的分配方式应该是这样的:
具体来讲也就是说,当值类型作为引用类型的私有字段时,它将作为引用类型实例的一部分,也分配在托管堆上。而当引用类型作为值类型的成员变量时,栈上将保留该成员的引用,其实际数据还是保存在堆中。
在C# 2出现之前,这样的说法没有问题。但C# 2引入了匿名方法和迭代器块后,以上说法就过于笼统了,它只看到了代码层面的东西,而没有看到编译器层面的东西。值类型实例作为局部变量不都是分配在栈上。这是因为C#代码中的局部变量,很可能在编译为IL后就不再是局部变量了。比如,如果匿名方法使用了外部变量(外部方法中声明的局部变量),或者迭代器块中声明了变量,那么这些变量将被提升为隐藏类的字段,因此也将分配在堆上。
由此可见,虽然MSDN的文档上也说,“值类型分配在栈上”,但这显然是不合适的。因为
这样,关于值类型的存储位置,正确、完整的说法应该是:对于值类型来说,在微软桌面CLR的C#实现中,如果值类型的实例是局部变量、Lambda表达式或匿名方法中封闭的临时变量,且方法体不是迭代器块,并且JIT不对该值进行寄存,那么这时该值类型将存储在栈上。
够啰嗦吧,其实每一句都必不可少:
之所以会有这样的误区,是因为人们总是错误地以为类型系统与存储分配策略有关。然而究竟是存储在栈上还是堆上,与要存储的类型没有任何关系。分配机制的选择只与存储所需的生存时间(lifetime)有关。
明确了这些之后,我们可以得出以下结论:
现在我们来看一下实现细节。在微软CLR对C#的实现中:
这样就可以很自然地得出:
一旦你摒弃值的类型与存储有关这个疯狂的想法,一切就会豁然开朗了。其实,你无需知道这些,除非要编写不安全代码或与非托管代码交互。你尽可以让编译器和运行时来管理存储位置的生存时间,这正是它们所擅长的。
下面我们来看一个关于引用的误区。虽然连《CLR via C#》中都有类似的描述:引用类型的变量保存的是对象的地址,但这是不正确的。引用类型的变量保存的是对象的引用。
引用是一个模糊的概念。指针与引用类似,可以通过跟踪其位置找到一些数据。但指针更智能,比如可以进行数学运算等。指针也更强大,引用能做的事,指针都能做,反之则不然。指针的缺点是对初学者来说太难理解了,很可能搬石头砸自己的脚。
指针是通过地址实现的。地址是一个数字,表示对进程的整个虚地址空间的一个偏移量(offset)。正因为地址是数字,所以才能对指针进行数学运算。
有些时候,指针是无法替代的;而大多数时候,又不需要这么复杂的概念。因此,C#中既包含指针,也包含引用。
C#语言规范中对引用的描述是十分模糊的:引用类型的变量存储了对某个对象的引用。同样,对指针的描述也是很模糊的:指针变量存储了对象的地址。不过,规范中从来没有说过引用就是地址。因此C#的引用是一个十分模糊的概念。你只能对一个引用进行解引用(dereference),或比较两个引用是否相等,除此之外不能进行任何操作。
实际上,在后台,对于托管对象的引用,CLR将其实现为GC所拥有的对象的地址。但这是实现细节。C#引用应该实现为只对GC有意义的不透明的句柄,只是这个句柄恰巧为运行时地址。这是实现细节,你既不应该知道,也不应该依赖于此。
所以,你不能说“引用即地址”这样的话。它并不是必须为地址,实现细节完全有可能改变。而且对初学者来说,你还要解释什么是地址,什么是偏移量。对了解指针的人来说,还会带来困扰:既然引用和指针都是地址,那么应该可以将引用转换为unsafe的指针。但这是不正确的。
综上所述,如果你不是要向别人解释C#的内存模型,请不要使用“引用即地址”这种论调。我们应该说:引用是一个小的数据块,它包含一些信息,CLR可以根据这些信息来找到引用所指向的对象。这很模糊,但却正确,并且没有多余的暗示。
你会发现,我们“无意中”从很多书籍和资料中了解到了CLR的实现细节,如果不是要深入研究这些细节,其实是没有必要知道的。我并不是说这些细节不重要,而是说它们会给我们带来误导,让我们误以为必须是这样。
你真的了解C#中的值和引用吗?(上),布布扣,bubuko.com
原文:http://www.cnblogs.com/schumi-lds/p/3644613.html