本文引用自:http://book.51cto.com/art/201109/292329.htm
很多初學者分不清readonly和const的使用場合。在我看來,要使用const的理由只有一個,那就是效率。但是,在大部分應用情況下,“效率”並沒有那麼高的地位,所以我更願意採用readonly,因為readonly賦予代碼更多的靈活性。const和readonly的本質區別如下:
const是一個編譯期常量,readonly是一個運行時常量。
const只能修飾基元類型、枚舉類型或字串類型,readonly沒有限制。
關於第一個區別,因為const是編譯期常量,所以它天然就是static的,不能手動再為const增加一個static修飾符,下面的代碼將會導致編譯通不過:
- static const int ConstValue = 100; //常量“ConstValue”不能標記為 static
而之所以說const變數的效率高,是因為經過編譯器編譯後,我們在代碼中引用const變數的地方會用const變數所對應的實際值來代替,如:
- Console.WriteLine(ConstValue);
和下面的代碼產生的IL代碼是一致的:
- Console.WriteLine(100);
readonly變數是運行時變數,其賦值行為發生在運行時。readonly的全部意義在於,它在運行時第一次被賦值後將不可以改變。當然,“不可以改變”分為兩層意思:
1)對於實值型別變數,值本身不可改變(readonly,唯讀)。
2)對於參考型別變數,引用本身(相當於指標)不可改變。
來看實值型別變數,查看如下代碼:
- class Sample
- {
- public readonly int ReadOnlyValue ;
-
- public Sample( int value)
- {
- ReadOnlyValue = value;
- }
- }
Sample的執行個體ReadOnlyValue在構造方法中被賦值後就不可以改變,下面的代碼將不會編譯通過:
- Sample sample = new Sample(200);
- sample.ReadOnlyValue = 300; //無法對唯讀字
- //段賦值(建構函式或變數初始值指定項中除外)
針對參考型別變數,查看如下代碼:
- class Sample2
- {
- public readonly Student ReadOnlyValue;
-
- public Sample2(Student value)
- {
- ReadOnlyValue = value;
- }
- }
Sample2的ReadOnlyValue是一個參考型別變數,賦值後,變數不能再指向任何其他的Student執行個體,所以,下面的代碼將不會編譯通過:
- Sample2 sample2 = new Sample2(new Student() { Age = 10 });
- sample2.ReadOnlyValue = new Student() { Age = 20 };
- //無法對唯讀欄位賦值(建構函式或變數初始值指定項中除外)
但是,我們之前已經提到過了,引用本身不可改變,引用所指的執行個體的值,卻是可以改變的,下面的代碼將會被允許:
- Sample2 sample2 = new Sample2(new Student() { Age = 10 });
- sample2.ReadOnlyValue.Age = 20;
readonly所代表的運行時含義有一個重要的作用,就是可以為每個類的執行個體指定一個readonly的變數。以Sample這個類為例,可以在運行時產生多個執行個體,而同時,又可以為每個執行個體產生自己的readonly變數,如下:
- Sample sample1 = new Sample(100);
- Sample sample2 = new Sample(200);
- Sample sample3 = new Sample(300);
這就是readonly變數所代表的運行時含義,也正是readonly變數的靈活之處。
注意 有人說,readonly變數不能被重新賦值是不正確的。下面的代碼錶明了它可以被改變:
- class Program
- {
- static void Main(string[] args)
- {
- Sample sample = new Sample(200);
- Console.WriteLine(sample.ReadOnlyValue);
- }
- }
-
- class Sample
- {
- public readonly int ReadOnlyValue = 100;
-
- public Sample(int value)
- {
- ReadOnlyValue = value;
- }
- }
ReadOnlyValue首先在初始值指定項(也稱為初始化器)中被賦值為100,後來,在構造方法中又被賦值為200。實際上,應該把初始化器理解成構造方法的一部分,它其實是一個文法糖。在構造方法內,我們確實可以多次對readonly賦值。