C#中有兩種常量類型县遣,分別為readonly(運(yùn)行時常量)與const(編譯時常量),本文將就這兩種類型的不同特性進(jìn)行比較并說明各自的適用場景耕拷。
工作原理
readonly為運(yùn)行時常量讼昆,程序運(yùn)行時進(jìn)行賦值,賦值完成后便無法更改骚烧,因此也有人稱其為只讀變量浸赫。
const為編譯時常量,程序編譯時將對常量值進(jìn)行解析赃绊,并將所有常量引用替換為相應(yīng)值既峡。
下面聲明兩個常量:
public static readonly int A = 2; //A為運(yùn)行時常量
public const int B = 3; //B為編譯時常量
下面的表達(dá)式:
int C = A + B;
經(jīng)過編譯后與下面的形式等價:
int C = A + 3;
可以看到,其中的const常量B被替換成字面量3碧查,而readonly常量A則保持引用方式运敢。
聲明及初始化
readonly常量只能聲明為類字段校仑,支持實(shí)例類型或靜態(tài)類型,可以在聲明的同時初始化或者在構(gòu)造函數(shù)中進(jìn)行初始化传惠,初始化完成后便無法更改迄沫。
const常量除了可以聲明為類字段之外,還可以聲明為方法中的局部常量卦方,默認(rèn)為靜態(tài)類型(無需用static修飾羊瘩,否則將導(dǎo)致編譯錯誤),但必須在聲明的同時完成初始化盼砍。
數(shù)據(jù)類型支持
由于const常量在編譯時將被替換為字面量困后,使得其取值類型受到了一定限制。const常量只能被賦予數(shù)字(整數(shù)衬廷、浮點(diǎn)數(shù))摇予、字符串以及枚舉類型。下面的代碼無法通過編譯:
public const DateTime D = DateTime.MinValue;
改成readonly就可以正常編譯:
public readonly DateTime D = DateTime.MinValue;
可維護(hù)性
readonly以引用方式進(jìn)行工作吗跋,某個常量更新后侧戴,所有引用該常量的地方均能得到更新后的值。
const的情況要稍稍復(fù)雜些跌宛,特別是跨程序集調(diào)用:
public class ClassA
{
public static readonly int A = 2; //A為運(yùn)行時常量
public const int B = 3; //B為編譯時常量
}
public class ClassB
{
public static int C = ClassA.A + ClassA.B; //變量C的值為A酗宋、B之和
}
Console.WriteLine(ClassB.C); //輸出"5"
假設(shè)Class1與Class2位于兩個不同的程序集,現(xiàn)在更改Class1中的常量值:
public class ClassA
{
public static readonly int A = 4; //A為運(yùn)行時常量
public const int B = 5; //B為編譯時常量
}
編譯ClassA并部署(注意:這時并沒有重新編譯ClassB)疆拘,再次查看變量C的值:
Console.WriteLine(ClassB.C); //輸出"7"
結(jié)果可能有點(diǎn)出乎意料蜕猫,讓我們來仔細(xì)觀察變量C的賦值表達(dá)式:
public static int C = ClassA.A + ClassA.B;
編譯后與下面的形式等價:
public static int C = ClassA.A + 3;
因此不管常量B的值如何變,對最終結(jié)果都不會產(chǎn)生影響哎迄。雖說重新編譯ClassB即可解決這個問題回右,但至少讓我們看到了const可能帶來的維護(hù)問題。
性能比較
const直接以字面量形式參與運(yùn)算漱挚,性能要略高于readonly翔烁,但對于一般應(yīng)用而言,這種性能上的差別可以說是微乎其微旨涝。
適用場景
在下面兩種情況下:
a.取值永久不變(比如圓周率蹬屹、一天包含的小時數(shù)、地球的半徑等)
b.對程序性能要求非嘲谆苛刻
可以使用const常量慨默,除此之外的其他情況都應(yīng)該優(yōu)先采用readonly常量。
C#中的static 和Java中的static
簡單弧腥,兩者用法完全是一致的厦取。從兩方面討論:
- 變量是屬于類的,不是實(shí)例級別的鸟赫。只能通過類名調(diào)用蒜胖,不能通過實(shí)例調(diào)用消别。
- 如果在定義時就賦值了,那么在類初始化的時候台谢,最先完成所有靜態(tài)變量的賦值寻狂。但是要注意,所有靜態(tài)變量的初始化順序是無法確定的朋沮。
C# 中的const 和Java中的finnal
很長一段時間我一直認(rèn)為兩者是相同的作用蛇券,無非是變量初始化后不能更改,即只能在定義時或者構(gòu)造函數(shù)中賦值樊拓。然而這僅僅只是片面的纠亚,下面將為大家詳細(xì)分析:
1.修飾變量
準(zhǔn)確的說C#中的const 等價于 Java中的static final,也就是說筋夏,Java中final不具有static的功能蒂胞。而C#中的const具有static的功能。因此在C#中 public static const string 等將于 public const string条篷。
2.修飾類和方法
此時Java中的final類似C#中的sealed骗随,就是說,final修飾的類不能被繼承赴叹,final修飾的方法不能被覆蓋鸿染。
而C#中的const不能修飾類和方法。
問題:
1. 私有靜態(tài)成員的作用(private static 變量)
字面表示私有的乞巧,類外不能使用涨椒;靜態(tài)的,全局變量绽媒〔隙看上去很矛盾,又不能被類外使用些椒,要全局的有什么用播瞳。問得好,類中全局也是很有意義的免糕,例如 private static int a = 5,那么就可以保證變量a在類的初始化過程中將被優(yōu)先初始化(在構(gòu)造函數(shù)執(zhí)行之前)忧侧。這樣如果對象A的初始化需要對象B的實(shí)例石窑,那么就可以用這種申明,以保證在類A在構(gòu)造函數(shù)中能夠使用類B的實(shí)例蚓炬。同時private又能夠保證類B的實(shí)例只能在類A中使用松逊,起到很好的密封作用。
2. 私有最終成員作用(private final 變量)
在類構(gòu)造函數(shù)完成前必須對該成員完成初始化肯夏,一旦定義不許更改经宏;該成員只能在本類中使用犀暑。實(shí)例,子類中都不能使用烁兰。
private static final修飾的成員在申明的時就被賦值耐亏,保證在構(gòu)造函數(shù)中可以被使用,一個被private static final修飾的成員通常表示其他組件的一個實(shí)例沪斟,且變量是類中的全局變量广辰。
private final 修飾的成員在構(gòu)造中被賦值,表示它是該類全局的私有成員變量主之,且該類的構(gòu)造需要傳入他們的初始值择吊,才能完成類的初始化。
C# const和static readonly區(qū)別
const:用const修飾符聲明的成員叫常量槽奕,是在編譯期初始化并嵌入到客戶端程序
static readonly: 用static readonly修飾符聲明的成員依然是變量几睛,只不過具有和常量類似的使用方法:通過類進(jìn)行訪問、初始化后不可以修改粤攒。但與常量不同的是這種變量是在運(yùn)行期初始化枉长。