文章目錄
- 運行時常量(readonly)和編譯時間常量(const)的不同
C#語言中有兩種類型的常量:編譯期常量和運行時常量。應該盡量使用運行時常量,而不是編譯期常量。雖然編譯期常量略快一些,但是沒有運行時常量那麼靈活。應僅僅在那些效能異常敏感,且常量的值在各個版本之間絕對不會變化時,才使用編譯器常量。
運行時常量使用readonly關鍵字聲明,編譯時間常量使用const關鍵字聲明:
1 //編譯時間常量,可以聲明在方法中2 public const int Millennium = 2000;3 //運行時常量,不能聲明在方法中4 public static readonly int ThisYear = 2012;
運行時常量(readonly)和編譯時間常量(const)的不同
二者的不同之處在於對它們的訪問方式不同。編譯時間常量的值是在在目標代碼中進行替換的,以下兩個構造生產的IL代碼時一樣的:
if(myDateTime.Year == Millennium)
if(myDateTime.Year == 2000)
這也就導致了編譯期常量僅能用於基本類型(內建的整數和浮點類型)、枚舉或字串。在編譯後得到的IL代碼中,只有這些常量可以直接被替換成為它們的字面值。
而運行時常量將在運行時求值,在建構函式執行後不能被再次修改。引用運行時常量產生的IL將引用到readonly的變數,而不是變數本身的值(靈活)。
二者的區別在於:readonly的值將在運行時給出,這會帶來更好的靈活性。例如,運行時常量可以為任意類型。readonly欄位必須在建構函式或初始化器中初始化,而 const 欄位只能在該欄位的聲明中初始化。
我們可以做一個假設:在一個名為Customer的程式集中分別定義了一個const欄位和readonly欄位:
1 class Customer2 {3 public static readonly int StartValue = 5;4 public const int EndValue = 10;5 }
在另一個程式集中引用了這兩個值,當我們過了一段時間需要更新Customer程式集的這兩個欄位將值更改:
1 class Customer2 {3 public static readonly int StartValue = 15;4 public const int EndValue = 20;5 }
隨後,分發Customer程式集,而沒有重新編譯整個應用程式時,我們可以發現在並沒有重寫編譯整個應用程式的情況下所以引用了readonly欄位的值變成了我們更新的值,而其他引用了const欄位的值卻沒有更新。
這是因為:
編譯器第一次編譯應用程式的時候:將所有引用了const欄位的變數的值替換成了它對應的常量值(5);對應所有引用readonly欄位的變數來說引用的是這個聲明為readonly的欄位,而不是其字面值。
所以說若想修改所有使用readonly的客戶代碼的行為,只需要簡單的更新一下這個聲明了readonly欄位的程式集就可以了。而想要更新所有使用const的客戶代碼的行為則需要重新編譯整個應用程式。
小結:
只有在編譯期必須獲得確定數值時一定要使用const。例如特性(attribute)的參數和枚舉的定義等,還有那些在各個版本發布之間不會變化的值。在除此之外的所以情況下,都應該經理選擇更加靈活的readonly常量。
閱讀書目:《Effective C#》