深入探討C#中的const、readonly關(guān)鍵字
首先不可否認(rèn),這些在面試上會(huì)經(jīng)常被面試官問起,但是你回答的讓面試官滿意嗎?當(dāng)然如果你知道了這些原理,或許你就不
怕了。既然說到了原理,我們還是從MSDN說起。
一:值得推敲的幾個(gè)地方
1.先來看看msdn上面對(duì)const是怎么說的,我們會(huì)看到。不能修改,編譯時(shí)常量這些關(guān)鍵性信息。

Q: const為什么不能被修改。
A:這個(gè)很簡單,很多教科書上面都說,當(dāng)編譯器編譯時(shí),會(huì)將常量的值保存在該程序集的元數(shù)據(jù)中,下面我們做個(gè)實(shí)例
看一看。
①:新建一個(gè)projectA。
// ProjectA
public class TestClass
{
public const int CTRIP = int.MaxValue;
}
再建一個(gè)MainProject,引用下projectA。
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(TestClass.CTRIP);
Console.Read();
}
}
然后我們把mainproject運(yùn)行起來。

既然我把mainproject跑起來了,并且也引用了Test.dll,剛才也說了,編譯的時(shí)候會(huì)把常量值保存在程序集的元數(shù)據(jù)中,那我們
就找一找,打開ILdasm.exe,并且Ctrl+M。

很可惜,我并沒有找到Ctrip的符號(hào),也沒有找到int.MaxValue,也沒有找到所謂的0x7fffffff,倒是找到了一個(gè)Assembly的一些版本信息的元數(shù)據(jù),那么這時(shí)候你可能會(huì)疑惑了,究竟const的值有沒有保存到Assembly里面去呢?很簡單的一個(gè)驗(yàn)證方法就是,把Mainproject下面bin中的Test.dll刪除掉,看看會(huì)有怎么樣的奇跡發(fā)生。


②: 聰明的你應(yīng)該想到了,既然運(yùn)行Demo.exe的時(shí)候不再加載Test.dll,而是直接從Demo的Assembly里面獲取const值,
那是不是會(huì)有斷層的事情發(fā)生,也就是版本不一致的情況,比如我已經(jīng)修改了const值,然后把編譯好的dll拷貝到Mainproject的bin目錄下,直接運(yùn)行Demo.exe,會(huì)不會(huì)出現(xiàn)MainProject讀不到修改后的const值呢?這里我將const改成 int.MinValue。
下面我們可以試試看。
// ProjectA
public class TestClass
{
public const int CTRIP = int.MinValue;
}


好了,看到上面的結(jié)果,就進(jìn)一步佐證了剛才的說法,const確確實(shí)實(shí)是保存在Assembly的元數(shù)據(jù)中,這里還要順便提示一下,Enum本質(zhì)上是const,所以它也存在我剛才說的斷層的問題,說到這里,我想你對(duì)const的原理應(yīng)該比較熟悉了,現(xiàn)在我們來看看Question的問題。既然是元數(shù)據(jù),那什么是元數(shù)據(jù)?“描述數(shù)據(jù)的數(shù)據(jù)” 叫做元數(shù)據(jù),既然它是基礎(chǔ)的描述性數(shù)據(jù),那么在定義好后是決對(duì)不能改變的,這個(gè)定義時(shí)也就是msdn說的編譯時(shí),是不是so easy呢?
Q: const為什么要做成靜態(tài)的,而不是做成實(shí)例的
A: 其實(shí)通過對(duì)第一個(gè)Question的分析,很多東西我們應(yīng)該都會(huì)豁然開朗,因?yàn)榇嬖跀鄬拥膯栴},那么最好的方法就是const的值
永遠(yuǎn)也不要變,這樣就可以避免問題的發(fā)生,既然是永遠(yuǎn)都不變的東西,當(dāng)然是跟著“類型”走比跟著“實(shí)例”走要好的多,你說對(duì)不對(duì),因?yàn)閟tatic是個(gè)小緩存,沒必要new一下才產(chǎn)生。。。
Q: readonly字段只能在ctor中初始化嗎?

A:這個(gè)問題蠻有意思的,我們知道readonly的意思就是只讀字段的意思,我們知道一般的字段具有可讀寫的功能,
先還是看看編譯器怎么說。

從編譯器上可以看到,確實(shí)readonly的初始化還可以在“變量初始化”的時(shí)候進(jìn)行初始化,那么這樣說Question的答案應(yīng)該就是否定的,但是真的是如此嗎?我們都知道有一個(gè)東西叫做“語法糖”,而且經(jīng)常是編譯器提供給我們用的,所以真正的想看到發(fā)生了什么,只能用ILDasm.exe 穿透編譯器,看看到底發(fā)生了什么。

從IL中可以看到,真的就是編譯器的語法糖,本質(zhì)上都是在ctor中初始化的,所以說,看問題千萬不要看表面。
注:Stsfld 用來自計(jì)算堆棧的值替換靜態(tài)字段的值。
相關(guān)文章
C#解析json字符串總是多出雙引號(hào)的原因分析及解決辦法
json好久沒用了,今天在用到j(luò)son的時(shí)候,發(fā)現(xiàn)對(duì)字符串做解析的時(shí)候總是多出雙引號(hào),下面給大家介紹C#解析json字符串總是多出雙引號(hào)的原因分析及解決辦法,需要的朋友參考下吧2016-03-03
DevExpress實(shí)現(xiàn)自定義TreeListNode的Tooltip的方法
這篇文章主要介紹了DevExpress實(shí)現(xiàn)自定義TreeListNode的Tooltip的方法,需要的朋友可以參考下2014-08-08

