.NET:也谈谈.NET中的引用类型和值类型
背景
引用类型和值类型的区别好像是一个经典的面试问题,也是一个非常基础的问题,今天试着写一下,一则为了以后新入职的毕业生学习,二则希望高手批评。
几个事实
- 值类型的局部变量始终分配在栈中,局部变量中存储的是值。
- 引用类型的局部变量始终分配在栈中,局部变量中存储的是值地址(引用),地址指向的值(对象)分配在堆中。
- 值类型的成员变量始终内敛存储在对象中(堆中),内敛存储的是值。
- 引用类型的成员变量始终内敛存储在对象中(堆中),内敛存储的是值地址(引用),地址指向的值(对象)分配在堆中的另外一个区域。
- 一个进程拥有多个AppDomain。
- 一个AppDomain拥有一个堆。
- 一个进程可以运行多个线程。
- 一个线程拥有一个栈(对于理解多线程编程非常有用)。
- 一个AppDomain中的所有线程之间共享一个堆(对于理解多线程编程非常有用)。
- 随着函数的调用和返回栈在不停的生长(调用)和消减(返回)。
- .NET默认是按值传递参数的。
- ref和out会导致按地址传递(栈的地址),也叫按引用传递。
注意事项:不要用C#中的这些事实理解Javascript、Ruby和Python等动态语言,一般会适得其反。
一个小测试
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace StackAndHeapStudy 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 { 14 var p = new Program(); 15 Console.WriteLine(p.GetHashCode()); 16 Do(ref p); 17 Console.WriteLine(p.GetHashCode()); 18 } 19 { 20 var p = new Program(); 21 Console.WriteLine(p.GetHashCode()); 22 Do(p); 23 Console.WriteLine(p.GetHashCode()); 24 } 25 } 26 27 static void Do(ref Program p) 28 { 29 p = new Program(); 30 } 31 32 static void Do(Program p) 33 { 34 p = new Program(); 35 } 36 } 37 }
备注
先把一些事实列出来,如果有朋友不是很明白,我再针对问题继续细化吧。