在C#中值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中。
常见的值类型数据有:整值型(整形,浮点型,十进制型),布尔类型,枚举类型;
引用类型有:接口,数组,Object类型,类,委托,字符串,null类型。
在C#中每种类型的存储方式有两种:1)分配在托管栈中;2)分配在托管堆中;
内存的分配有CLR管理(即公共语言运行时),这两种方法的区别是:
1)分配在托管栈中的变量会在创建它们的方法返回时自动释放,例如在一个方法中声明Char型的变量UserInput=C,当实例化它的方法结束时,UserInput变量在栈上占用的内存就会自动释放;
2)分配在托管堆中的变量并不会在创建它们的方法结束时释放内存,它们所占用的内存会被CLR中的垃圾回收机制释放。
看下面的代码:
1 static void Main(string[] args) 2 { 3 //当nStudent声明并赋值是,这时在托管栈上就会开辟一块内存来存储nStudent的值,当实例化nStudent的Main()方法结束时, 4 //nStudent在托管栈上占用的内存会自动释放。 5 int nStudent = 0; 6 //当声明strStuName时,这个时候“小明”存储在托管堆中,而托管栈中存储的是strStuName指向的引用。 7 string strStuName = "小明"; 8 9 Console.WriteLine("学生的总数是{0},五号的名字是{1}", nStudent, strStuName); 10 Console.ReadKey(); 11 }
装箱和拆箱
当值类型的数据转换成引用类型时,CLR会先在托管堆配置一块内存,将值类型的数据复制到这块内存,然后再让托管栈上的引用类型的变量指向这块内存,这样的过程称为装箱。相反的话,有引用类型转换成值类型的话就称为拆箱。
一般情况下,.NET会主动的帮我们完成装箱操作,但是拆箱并非主动,我们必须知道拆箱对象的实力类型,然后明确的去执行拆箱操作。
1 int BirthdayNum = 1989; 2 object BoxBirthdayNum = BirthdayNum;//系统自动装箱 3 int nBirthdayNum = (int)BoxBirthdayNum;//明确数据类型的拆箱
因为花费了更多的时间,所以装箱和拆箱对程序的性能有一定的影响。
--------------------------------------------------------------------------------------------------------------------------------------
类型推断
从C#3.0开始,C#引入了一个隐式类型推断的关键字var,编译器可以通过它的初始值来判断变量的具体类型。var只能用于局部变量的声明,不能用于字段级的变量声明。使用var关键字时,var必须得有初始值,这样编译器才能判断是否是真实变量。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var i = 10;//隐式类型 6 int m = 10;//显示类型 7 8 var Program=new Program(); 9 Program.nAge = 20; 10 Program.SayHello(); 11 } 12 13 private int nAge; 14 public void SayHello() 15 { 16 var message = "my age is {0}"; 17 Console.WriteLine(message, nAge); 18 } 19 }
message初始值的变量为字符串类型,因此编译器可以推断其类型为String类型。