在C#中值類型的變量直接存儲數(shù)據(jù),而引用類型的變量持有的是數(shù)據(jù)的引用,數(shù)據(jù)存儲在數(shù)據(jù)堆中。
常見的值類型數(shù)據(jù)有:整值型(整形,浮點型,十進制型),布爾類型,枚舉類型;
引用類型有:接口,數(shù)組,Object類型,類,委托,字符串,null類型。
在C#中每種類型的存儲方式有兩種:1)分配在托管棧中;2)分配在托管堆中;
內(nèi)存的分配有CLR管理(即公共語言運行時),這兩種方法的區(qū)別是:
1)分配在托管棧中的變量會在創(chuàng)建它們的方法返回時自動釋放,例如在一個方法中聲明Char型的變量UserInput=C,當實例化它的方法結束時,UserInput變量在棧上占用的內(nèi)存就會自動釋放;
2)分配在托管堆中的變量并不會在創(chuàng)建它們的方法結束時釋放內(nèi)存,它們所占用的內(nèi)存會被CLR中的垃圾回收機制釋放。
看下面的代碼:
1 static void Main(string[] args)
2 {
3 //當nStudent聲明并賦值是,這時在托管棧上就會開辟一塊內(nèi)存來存儲nStudent的值,當實例化nStudent的Main()方法結束時,
4 //nStudent在托管棧上占用的內(nèi)存會自動釋放。
5 int nStudent = 0;
6 //當聲明strStuName時,這個時候“小明”存儲在托管堆中,而托管棧中存儲的是strStuName指向的引用。
7 string strStuName = "小明";
8
9 Console.WriteLine("學生的總數(shù)是{0},五號的名字是{1}", nStudent, strStuName);
10 Console.ReadKey();
11 }
裝箱和拆箱
當值類型的數(shù)據(jù)轉換成引用類型時,CLR會先在托管堆配置一塊內(nèi)存,將值類型的數(shù)據(jù)復制到這塊內(nèi)存,然后再讓托管棧上的引用類型的變量指向這塊內(nèi)存,這樣的過程稱為裝箱。相反的話,有引用類型轉換成值類型的話就稱為拆箱。
一般情況下,.NET會主動的幫我們完成裝箱操作,但是拆箱并非主動,我們必須知道拆箱對象的實力類型,然后明確的去執(zhí)行拆箱操作。
1 int BirthdayNum = 1989; 2 object BoxBirthdayNum = BirthdayNum;//系統(tǒng)自動裝箱 3 int nBirthdayNum = (int)BoxBirthdayNum;//明確數(shù)據(jù)類型的拆箱
因為花費了更多的時間,所以裝箱和拆箱對程序的性能有一定的影響。
--------------------------------------------------------------------------------------------------------------------------------------
類型推斷
在C#中有兩種類型的數(shù)據(jù),一種是值類型,另一種是引用類型。
值類型包括:內(nèi)置值類型、用戶自定義值類型、和枚舉,如 int,float bool 等,以及struct等。
引用類型包括接口類型、用戶自定義的類、委托等。如 string 、DateTime、數(shù)組等。
值類型是存儲在堆棧中,而引用類型是存儲在托管堆上,C#程序首先被編譯成IL程序,然后在托管執(zhí)行。值類型直接從堆棧中里面取值,而引用類型必須要先從堆棧里面取出它的地址,再根據(jù)這個地址在堆里找到對應的值。
值類型與飲用類型的本質區(qū)別有以下幾點:
1.內(nèi)存分配: 值類型是分配在棧中的;而引用類型是分配在堆中。
2.效率: 值類型效率高,不需要地址轉換;引用類型效率較低,需要進行地址轉換。
3.內(nèi)存回收: 值類型使用完后立即回收;引用類型使用完后不立即回收,而是交給GC處理回收。
4.賦值操作: 值類型是創(chuàng)建一個新對象;引用類型創(chuàng)建一個引用。
5.類型擴展: 值類型不易擴展,所有值類型都是密封(seal)的,所以無法派生出新的值類型;引用類型具有多態(tài)的特性方便擴展。
這是別人的總結,我在這里拿來用下。
下面我在說說它們在用法上的區(qū)別了,C#之所以要分這兩種數(shù)據(jù)類型的原因是達到更好的性能,把一些基本類型如int、bool規(guī)定為值類型,而把包含許多字段的較大類型規(guī)定為引用類型,如用戶自定義的類。值類型主要是負責存儲數(shù)據(jù),引用類更多是用在代碼的重用性上。
從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類型。