1.基元類型
編譯器直接支援的資料類型成為基元類型。基元類型與FCL中的類型有直接的映射關系[int=Int32],這樣我們可以簡化的方式書寫代碼,并且編譯後的IL和直接使用FCL中的資料類型是完全相同的。
Checked和Unchecked操作:
Byte b=100;
b=(Byte)(b+200);
CLR隻在32位和64位上進行算數運算,是以b首先會被轉換為32位的值再和100相加,得到的是32位的值,接着轉型為Byte,再然後将其放入b的存儲堆棧。但是b的結果是44,反生了溢出,并不是期望的300[當然b也存不下300],然而卻并沒提示什麼異常或錯誤。這是因為C#編譯器預設是不檢查溢出的。可以使用/checked+指令行開關。但是這是針對所有的代碼都進行溢出檢查,會試代碼的效率有所下降。C#中的checked和unchecked操作符則提供了更好的靈活性。
b=checked((Byte)(b+200));這樣再運作此行的話就會抛出 System.OverflowException[算術運算導緻溢出]異常;相反unchecked則是不檢查溢出,不會抛出異常。
System.Decimal是一個特殊的類型,雖然C#把它當作基元類型,但是CLR卻不是,意味着CLR沒有直接操作Decimal的IL指令,檢視msdn中Decimal類型的文檔可以發現它提供了Add、Divide、、、靜态方法及一些操作符[+-*/...]重載方法,當我們使用它的值運算時實際上是調用它的成員來執行的,是以效率會比其他基元類型差些[CLR為其他基元類型直接提供了運算的IL指令,省去了操作符的重載],因為也沒IL指令,是以checked和unchecked對它沒有任何影響,如果對它的操作沒有安全執行,則抛出System.OverflowException異常。
2.引用類型和值類型:
作為局部變量時值類型位于線程堆棧上,引用類型位于托管堆;作為類型成員時,則由其所屬類型決定。托管代碼中,我們定義的類型決定了它在記憶體中的配置設定位置,而我們對此沒有控制的權限。另外值類型不受GC的控制。C#中值類型不允許定義Finalize方法[隻有值類型裝箱後才可能被調用],CLR允許,但是CLR執行垃圾清理時比不會調用它,是以為值類型定義Finaliza方法是沒有意義的。
控制類型中字段的布局:System.Runtime.InteropServices.StructLayout特性來告訴CLR如何布局類型中的字段;C#編譯器為引用類型選LayoutKind.Auto,讓CLR自己排列字段。為值類型選擇LayoutKind.Sequential,讓CLR保留我們自己定義的字段布局。當然我們也可以通過此特性來改變編譯器的預設行為。
3.裝箱和拆箱
裝箱過程:從托管堆中為新生成的引用類型對象配置設定記憶體[大小是值類型成員本身的大小加上附加成員的大小];再把值類型的執行個體字段拷貝到托管堆上新對象的記憶體中,然後傳回對象的引用。
拆箱過程:擷取指向對象中包含的值類型部分[資料字段]的指針,不會涉及字段拷貝。
然而緊接着拆箱之後的典型操作往往是字段拷貝。--是以裝箱和[拆箱+字段拷貝]總體互反。另外裝箱操作裝進去什麼類型就要拿什麼類型來拆,不然你裝進去一個大蘋果[int],拆除一個小蘋果[byte]、或者拆出一個string[桔子],你會願意嗎?裝箱和拆箱\字段拷貝會從速度和記憶體上損傷程式的性能。盡量的避免這些操作
作者:
Blackheart出處:
http://linianhui.cnblogs.com本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。