Effective c# Item2:運行時常量(readonly)優於編譯時間常量(const)

來源:互聯網
上載者:User
   c#有兩種不同版本的常量:編譯時間常量和運行時常量。它們有完全不同的行為,如果用的不好將花費額外效能甚至出錯。如果你一定要選擇其一,一個慢但正確的程式總比一個快的錯的程式好,所以你應該選擇運行時常量而不是編譯時間常量。編譯時間常量相對運行時常量雖然快,但並不靈活。當涉及程式效能並且其值不會改變時我們應該保留編譯時間常量。
   定義運行時常量用關鍵字readonly ,編譯時間常量用關鍵字const 聲明:// Compile time constant:
public const int _Millennium = 2000;
// Runtime constant:
public static readonly int _ThisYear = 2004;

   編譯時間常量與運行時常量的行為區別是從怎樣訪問它們得出的。在你的目標代碼中編譯時間常量替換為其值,下面的代碼:if ( myDateTime.Year == _Millennium )

   如果你寫成下面那樣,那麼將編譯成同樣的IL代碼:if ( myDateTime.Year == 2000 )

   當你引用read-only常量時,產生的IL代碼引用readonly 變數而不是其值。
   當你使用兩者其一時,這些區別就會在一些限制上表現出來。編譯時間常量只能被用於基本類型,枚舉,字串。這些是你可以在初始化時指定的常量的唯一的類型。唯有這些基本類型才能在編譯IL代碼時直接用其字面值替代。下面這段代碼不能通過編譯,你不能用new操作符初始化一個編譯時間常量,甚至其類型是實值型別:// Does not compile, use readonly instead:
private const DateTime _classCreation = new
  DateTime( 2000, 1, 1, 0, 0, 0 );

   編譯時間常量僅局限於數學型及字串型。唯讀變數也是常量,它們不能在其建構函式執行完後改變。但唯讀變數的值是可以改變的,因為其值是在運行時指定的。運用運行時常量有更大的靈活性,而且它可以是任何類型。你必須在建構函式中初始化它們,或可以用初始化函數。你可以建立一個DateTime結構類型的唯讀變數,但不能建立一個const常量。
   唯讀變數可以是靜態也可以不是,但編譯時間常量從其定義只能是靜態(static)的。
   比較重要的區別是唯讀變數的值是在運行時指定。當你引用唯讀變數IL代碼引用的是其唯讀變數而非其值。這種區別表現在於其維護性上。編譯時間常量產生同樣的IL代碼如同在你代碼中使用數字型常量,甚至跨程式集時也這樣:一個程式集裡的常量在另一程式集中仍保留同樣的值。
   編譯時間常量和運行時常量賦值方式不同可能影響運行時的相容性。假定你在程式集Infrastructrue中定義了const和readonly常量欄位:

public class UsefulValues
{
  public static readonly int StartValue = 5;

  public const int EndValue = 10;
}

   在另一程式集中,你引用了它們:for ( int i = UsefulValues.StartValue;
  i < UsefulValues.EndValue;
  i++ )
  Console.WriteLine( "value is {0}", i );

   你可以看到明顯的結果:Value is 105
Value is 106

Value is 119

   隨著時間過去,你有了一個程式集Infrastructrue新的版本:public class UsefulValues
{
  public static readonly int StartValue = 105;

  public const int EndValue = 120;
}

   你在沒有重建程式集的情況下發布你的新程式集,你期望得到下面的值:Value is 105
Value is 106

Value is 119

   實際上,並無輸出。因為這個迴圈以105開始10結束。c#編譯器將常量的值10置入應用程式集中,替代EndValue儲存的值。與StartValue的值相比,它聲明為唯讀,意味著可以在運行時取值,因此應用程式集在沒有重新編譯的情況下取其新值,簡單的安裝一下更新後的程式集就可以改變所有客戶用的值。更新一個公用常量的值可以看作是介面的改變,你必須重新編譯用到這個值的所有代碼。更新一個唯讀變數你可以看作是實現的改變,它對客戶代碼是二進位相容的。對上面那段迴圈進行驗證MSIL代碼你會發現為什麼會這樣:IL_0000:  ldsfld     int32 Chapter1.UsefulValues::StartValue
IL_0005:  stloc.0
IL_0006:  br.s       IL_001c
IL_0008:  ldstr      "value is {0}"
IL_000d:  ldloc.0
IL_000e:  box        [mscorlib]System.Int32
IL_0013:  call       void [mscorlib]System.Console::WriteLine
    (string,object)
IL_0018:  ldloc.0
IL_0019:  ldc.i4.1
IL_001a:  add
IL_001b:  stloc.0
IL_001c:  ldloc.0
IL_001d:  ldc.i4.s   10
IL_001f:  blt.s      IL_0008

   你會發現在MSIL代碼中StartValue值是動態裝載的,但是EndValue值是被硬式編碼。
   另一方面,有時你也要用編譯時間常量。例如,考慮一個對象的不同版本的情況,你應用編譯時間常量對應不同的版本,因為它們決不會改變。而現有版本則應該使用運行時常量,因為每次發布後版本號碼不一樣:private const int VERSION_1_0 = 0x0100;
private const int VERSION_1_1 = 0x0101;
private const int VERSION_1_2 = 0x0102;
// major release:
private const int VERSION_2_0 = 0x0200;

// check for the current version:
private static readonly int CURRENT_VERSION =
  VERSION_2_0;

   你對每個儲存的檔案使用運行時常量值:// Read from persistent storage, check
// stored version against compile-time constant:
protected MyType( SerializationInfo info,
  StreamingContext cntxt )
{
  int storedVersion = info.GetInt32( "VERSION" );
  switch ( storedVersion )
  {
  case VERSION_2_0:
    readVersion2( info, cntxt );
    break;
  case VERSION_1_1:
    readVersion1Dot1( info, cntxt );
    break;

  // etc.
  }
}

// Write the current version:
[ SecurityPermissionAttribute( SecurityAction.Demand,
  SerializationFormatter =true ) ]
void ISerializable.GetObjectData( SerializationInfo inf,
    StreamingContext cxt )
{
  // use runtime constant for current version:
  inf.AddValue( "VERSION", CURRENT_VERSION );

  // write remaining elements
}

   const常量最後一個優於readonly常量的地方就是效能:訪問const常量相對readonly常量可以更快捷有效,但你必須權衡效能及靈活性,在你放棄靈活性前你得確信剖析過效能。
   const常量用在編譯時間必須確定值的情況:屬性參數,枚舉定義和那些不會隨著版本發布而改變值的常量。無論怎樣,強烈建議你使用靈活性強的運行時常量。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.