編譯器能夠直接支援的資料類型叫做基元類型。例如int, string等。基元類型和.NET架構類庫FCL存在着直接的映射關系。
string和String?
面試的時候曾經被問到過這個問題,C#中的基元類型string實際上對應了System.String(FCL)類型,是以兩者使用的時候沒有什麼不同。
類型轉換
編譯器能夠在基元類型之間進行顯式或隐式轉換。如果轉換是安全的,也就是轉換過程不會造成資料丢失,則可以直接采用隐式轉換。如果是不安全的,則必須采用顯式轉換。
Int32 a=5; Int64 b=a; Int32 c=(Int32)b;
引用類型和值類型的差別:
引用類型
值類型
從托管堆中配置設定
從線程的堆棧中配置設定
對象考慮垃圾回收機制
不考慮垃圾回收機制
所有類都是引用
結構或枚舉都是值類型
繼承自System.ValueType
隻有裝箱形式
有兩種形式:裝箱和未裝箱
可以繼承和派生
不能作為基類,不能有虛方法
引用類型變量初始化時預設為null
初始化時預設為0值
複制時隻拷貝記憶體位址
複制時“字段對字段”的拷貝
結構體直接繼承自System.ValueType;而枚舉直接繼承自System.Enum, Enum類又直接繼承自System.ValueType。
下面通過例子看一下他們的差別:
首先定義類和結構體:
class SomeRef { public Int32 x; } struct SomeVal { public Int32 x; }
SomeRef r1 = new SomeRef(); // 配置設定到堆 SomeVal v1 = new SomeVal(); // 配置設定到棧 r1.x =5; // 所引用的堆空間内資料修改 v1.x =5; // 直接在棧上複指派 Console.WriteLine(r1.x); // "5" Console.WriteLine(v1.x); // "5" SomeRef r2 = r1; //隻把指針複制給了r2 SomeVal v2 = v1; // 在棧上配置設定空間,并且将變量内容進行複制 r1.x = 8; // r1指向(也是r2指向)的内容修改 v1.x = 9; // 隻修改v1内容,v2内容不會受影響 Console.WriteLine(r1.x); // "8" Console.WriteLine(r2.x); // "8" Console.WriteLine(v1.x); // "9" Console.WriteLine(v2.x); // "5"
看看下圖的記憶體配置設定情況,就一目了然了。
<a href="http://images.cnblogs.com/cnblogs_com/janes/201107/201107041634175932.png"></a>
1. 裝箱過程?
裝箱:将值類型轉換為引用類型。當我們把值類型參數傳遞給需要引用類型參數的方法時,會自動進行裝箱操作。過程如下:
從托管堆為要生成的引用類型配置設定大小。大小為:值類型執行個體本身的大小+額外空間(方法表指針和SyncBlockIndex)。
将值類型字段拷貝到剛剛配置設定的記憶體中。
傳回托管堆中新配置設定記憶體的位址。也就是指向對象的引用。
2. 拆箱過程?
拆箱:擷取指向對象中包含的值類型部分的指針。一般拆箱之後會進行字段拷貝操作,兩個操作加起來才是真正與裝箱互反的操作。過程如下:
如果引用為Null,則抛出NullReferenceException異常。
如果引用對象不是一個期望值類型的已裝箱對象,會抛出InvalidCastException異常。
傳回一個指向包含在已裝箱對象中值類型部分的指針。
3. 執行個體
拆箱的轉型結果必須是它原來未裝箱時的類型。
public static void Main() { Int32 x = 5; Object o = x; // 裝箱 Int16 y = (Int16) o; // 拆箱,抛出InvalidCastException異常 }
修正:Int16 z=(Int16)(Int32)o;//拆箱成功
這段代碼進行了幾次裝箱?
Int32 v = 5; // 建立值變量 Object o = v; // 裝箱 v = 123; // Changes the unboxed value to 123 Console.WriteLine(v + ", " + (Int32) o); // Displays "123, 5" ,裝箱兩次
上面的代碼進行了3次裝箱,最後一行中v被裝箱為引用類型,o首先被拆箱然後再裝箱為引用類型。
我們看一下它的IL代碼:
<a href="http://images.cnblogs.com/cnblogs_com/janes/201110/201110211045546354.jpg"></a>
字元串連接配接實際上調用的是Concat方法,該方法的參數要求是object,是以各參數都要轉換成object類型。
優化:
Console.WriteLine(v.ToString()+”,”+o);//裝箱0次
我們要盡量少的進行值類型的裝箱拆箱操作,以提高程式性能。
本文轉自 陳敬(Cathy) 部落格園部落格,原文連結:http://www.cnblogs.com/janes/archive/2011/07/04/2097540.html,如需轉載請自行聯系原作者