天天看點

2.在 readonly 和 const 之間,優先使用 readonly

C#中有兩種常量類型,分别為readonly(運作時常量)與const(編譯時常量),本文将就這兩種類型的不同特性進行比較并說明各自的适用場景。

工作原理

    readonly為運作時常量,程式運作時進行指派,指派完成後便無法更改,是以也有人稱其為隻讀變量。

    const為編譯時常量,程式編譯時将對常量值進行解析,并将所有常量引用替換為相應值。

    下面聲明兩個常量:

<程式代碼>

public static readonly int A = 2; //A為運作時常量

public const int B = 3; //B為編譯時常量

下面的表達式:

<程式代碼>

int C = A + B;

經過編譯後與下面的形式等價:

<程式代碼>

int C = A + 3;

    可以看到,其中的const常量B被替換成字面量3,而readonly常量A則保持引用方式。

聲明及初始化

    readonly常量隻能聲明為類字段,支援執行個體類型或靜态類型,可以在聲明的同時初始化或者在構造函數中進行初始化,初始化完成後便無法更改。

    const常量除了可以聲明為類字段之外,還可以聲明為方法中的局部常量,預設為靜态類型(無需用static修飾,否則将導緻編譯錯誤),但必須在聲明的同時完成初始化。

資料類型支援

    由于const常量在編譯時将被替換為字面量,使得其取值類型受到了一定限制。const常量隻能被賦予數字(整數、浮點數)、字元串以及枚舉類型。下面的代碼無法通過編譯:

<程式代碼>

public const DateTime D = DateTime.MinValue;

改成readonly就可以正常編譯:

<程式代碼>

public readonly DateTime D = DateTime.MinValue;

可維護性

    readonly以引用方式進行工作,某個常量更新後,所有引用該常量的地方均能得到更新後的值。

    const的情況要稍稍複雜些,特别是跨程式集調用:

<程式代碼>

public class Class1

{

    public static readonly int A = 2; //A為運作時常量

    public const int B = 3; //B為編譯時常量

}

public class Class2

{

    public static int C = Class1.A + Class1.B; //變量C的值為A、B之和

}

Console.WriteLine(Class2.C); //輸出"5"

假設Class1與Class2位于兩個不同的程式集,現在更改Class1中的常量值:

 <程式代碼>

public class Class1

{

    public static readonly int A = 4; //A為運作時常量

    public const int B = 5; //B為編譯時常量

}

    編譯Class1并部署(注意:這時并沒有重新編譯Class2),再次檢視變量C的值:

<程式代碼>

Console.WriteLine(Class2.C); //輸出"7"

    結果可能有點出乎意料,讓我們來仔細觀察變量C的指派表達式:

<程式代碼>

public static int C = Class1.A + Class1.B;

    編譯後與下面的形式等價:

<程式代碼>

public static int C = Class1.A + 3;

    是以不管常量B的值如何變,對最終結果都不會産生影響。雖說重新編譯Class2即可解決這個問題,但至少讓我們看到了const可能帶來的維護問題。

性能比較

    const直接以字面量形式參與運算,性能要略高于readonly,但對于一般應用而言,這種性能上的差别可以說是微乎其微。

适用場景

    在下面兩種情況下:

    a.取值永久不變(比如圓周率、一天包含的小時數、地球的半徑等)

    b.對程式性能要求非常苛刻

    可以使用const常量,除此之外的其他情況都應該優先采用readonly常量。