1.常量
常量是永遠不會改變的符號。它的值必須在編譯時就確定。編譯後,CLR將常量的值保存在Assembly的 元數據中,這意味著常量必須是基元類型。
常量是類型的一部分,總是被當成靜態成員,但並不顯示聲明為static。
public const Int32 MaxEntriesList = 100;
當代碼引用常量時,CLR在元數據中查找該符號,將提取的常量值嵌入到IL中,所以常量沒有地址以及 相應的分配內存,而且不能通過引用傳遞變量,也就是說,在導入一個外部的DLL時,就已經將其中的常 量嵌入到自身工程的IL中來了,可以刪除這個DLL,而不對當前產生任何影響;即使在DLL中改變常量的值 並重新編譯該DLL,也不會對自身工程產生影響(還是過去的常量值,而不是新值);只有重新編譯自身工 程,才能獲取到新的常量值——這就是說,常量沒有很好的跨程序集版本控制特性。
2.字段field
字段區別於常量,傳遞的是引用,可以是任何數據類型。
有類型(靜態)字段和實例字段兩種。
對於靜態字段,在類型加載到AppDomain時才創建,即首次引用類型的時候——JIT編譯;
對於實例字段,創建實例時才分配字段的動態內存
readonly關鍵字,在MSIL中相應為InitOnly,有此關鍵字的字段只能在ctor中可寫,在其他地方是只 讀的(可以使用反射修改readonly字段)。
volatile關鍵字,見線程同步筆記。
public static readonly Int32 MaxEntriesList = 100;
由於字段是基於引用的,所以不會直接嵌入IL元數據,從而編譯含有字段的DLL,會對使用該DLL的工 程造成影響,從而實現了版本控制,總是使用最新的DLL。
多數字段使用內聯初始化的。CLR建議這麼做,具體的參見 《C# 50個有效的方法》,但是在內聯中不 可以使用方法/屬性。
內聯初始化在ctor/cctor之前。
繼續看readonly關鍵字,使用在引用類型的字段上,標志著該字段是不可改變的引用,而不是不可改 變的對象,如下示例:
public sealed class AType { public static readonly Char[] InvalidChars = new Char[] { 'A', 'B', 'C' }; } public sealed class AnotherType { public static void M() { //以下3行是合法的,因為InvalidChars引用的值可以更改 AType.InvalidChars[0] = 'X'; AType.InvalidChars[1] = 'Y'; AType.InvalidChars[2] = 'Z'; //以下1行是不合法的,不能通過編譯,因為InvalidChars的引用無法更改 AType.InvalidChars = new Char[] { 'X', 'Y', 'Z' }; } }
補充:
實例方法中可以使用靜態變量;
靜態方法中不可以使用實例變量。