[C#.NET] 定義常數時用 readonly 好? 還是 const 好?
在C#內我們可以使用兩種方式來宣告常數,const (C# 參考)、readonly (C# 參考)。
執行階段常數readonly
public static readonly int Start = 0;
編譯時期常數const
public const int End = 10;
兩種方式有相同的意義但背卻有不同的運作行為,使用不當的話可能會造成一些問題發生,我們在定義常數的時候會建議使用readonly而不是const,雖然說使用const的效能比使用static readonly效能好一些,但是整體的靈活性及方便性都是static readonly勝出的。
1.const 僅能用於數字和字串,而readonly可以是任意型態。
2.const能在方法中使用,readonly不行。(常數不應該是宣告在方法裡)
3.const 是在編譯時期產生的,readonly是在運行時產生的,假設我在有一個方法
在IL底下會看到以下:
用Reflector會看到以下:
引用一個readonly常數時是引用其變數,而引用const是引用其值,這將會影響執行時的相容性。
接下來我們來看看對於實際的專案它們兩個會有什麼不同??
首先我先建立一個類別庫專案並輸入ClassLibrary1
namespace ClassLibrary1
{
public class Class1
{
public static readonly int Start = 0;
public const int End = 10;
}
}
然後再建立一個主控台應用程式,加入ClassLibrary1.dll
在main使用了Class1.Start及Class1.End
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
for (int i = Class1.Start; i < Class1.End; i++)
{
Console.WriteLine("value is {0}", i);
}
Console.ReadKey();
}
}
}
執行結果如下:
在ConsoleApplication1.exe裡我們一直快樂的使用這兩個常數,ConsoleApplication1.exe也很正常的在客戶端執行著,有天PM跟我講說常數的定義有誤,必須要修改一下,很直覺的我只修改了ClassLibrary1裡的常數並編譯成dll,然後將ClassLibrary1.dll發佈到上去(將dll檔案copy到ConsoleApplication1.exe相對應資料夾),然後直接執行ConsoleApplication1.exe。
namespace ClassLibrary1
{
public class Class1
{
public static readonly int Start = 9;
public const int End = 20;
}
}
怪了,直接跑 ConsoleApplication1.exe 的執行結果怎麼跟我想的不太一樣。
追根究底一下,原來Class.End編譯後變成10,難怪結果不是對的。
把ConsoleApplication1.exe專案打開來重新編譯就能得到我要的結果了,需要重新編譯的應用程式表示抽換的還不夠乾淨或是有其他問題,如果一個大的系統裡面全部的檔案都需要重新編譯,表示你需要更新的檔案不只一個。
後記:
本來將專案設計的相關靈活,用戶可以很容易抽換,直接拿新版的dll蓋過去就好,但是沒注意到背後的運作原理反倒會被將了一軍;聰明的你看完小的實作相信你應該知道要選什麼好了。
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET