const,readonly 這些你真的懂嗎? 也許會被面試到哦。。。

一線碼農發表於2014-07-19

 

  首先不可否認,這些在面試上會經常被面試官問起,但是你回答的讓面試官滿意嗎?當然如果你知道了這些原理,或許你就不

怕了。既然說到了原理,我們還是從MSDN說起。

     

一:值得推敲的幾個地方

 1.先來看看msdn上面對const是怎麼說的,我們會看到。不能修改,編譯時常量這些關鍵性資訊。

 

Q:  const為什麼不能被修改。

 

A:這個很簡單,很多教科書上面都說,當編譯器編譯時,會將常量的值儲存在該程式集的後設資料中,下面我們做個例項

     看一看。

 

   ①:新建一個projectA。

1 // ProjectA
2 public class TestClass
3 {
4     public const int CTRIP = int.MaxValue;
5 }

   再建一個MainProject,引用下projectA。

 1 using System;
 2 
 3 class Program
 4 {
 5     static void Main(string[] args)
 6     {
 7         Console.WriteLine(TestClass.CTRIP);
 8 
 9         Console.Read();
10     }
11 }

    然後我們把mainproject執行起來。

 

    既然我把mainproject跑起來了,並且也引用了Test.dll,剛才也說了,編譯的時候會把常量值儲存在程式集的後設資料中,那我們

就找一找,開啟ILdasm.exe,並且Ctrl+M。

 

 

   很可惜,我並沒有找到Ctrip的符號,也沒有找到int.MaxValue,也沒有找到所謂的0x7fffffff,倒是找到了一個Assembly

的一些版本資訊的後設資料,那麼這時候你可能會疑惑了,究竟const的值有沒有儲存到Assembly裡面去呢?很簡單的一個驗證

方法就是,把Mainproject下面bin中的Test.dll刪除掉,看看會有怎麼樣的奇蹟發生。

 

 

  這時候你會發現,既然test.dll都刪除了。Demo.exe既然還能執行起來,說明const的值真的是寫入到了Assembly裡面

去了。不然值從哪裡來的呢?

 

 ②: 聰明的你應該想到了,既然執行Demo.exe的時候不再載入Test.dll,而是直接從Demo的Assembly裡面獲取const值,

       那是不是會有斷層的事情發生,也就是版本不一致的情況,比如我已經修改了const值,然後把編譯好的dll拷貝到Mainproject

       的bin目錄下,直接執行Demo.exe,會不會出現MainProject讀不到修改後的const值呢?這裡我將const改成 int.MinValue。

       下面我們可以試試看。

1 // ProjectA
2 public class TestClass
3 {
4     public const int CTRIP = int.MinValue;
5 }

    

 

好了,看到上面的結果,就進一步佐證了剛才的說法,const確確實實是儲存在Assembly的後設資料中,這裡還要順便提示

一下,Enum本質上是const,所以它也存在我剛才說的斷層的問題,說到這裡,我想你對const的原理應該比較熟悉了,現

在我們來看看Question的問題。既然是後設資料,那什麼是後設資料?“描述資料的資料” 叫做後設資料,既然它是基礎的描述性

據,那麼在定義好後是決對不能改變的,這個定義時也就是msdn說的編譯時,是不是so easy呢?

 

Q:  const為什麼要做成靜態的,而不是做成例項的

 

A:  其實通過對第一個Question的分析,很多東西我們應該都會豁然開朗,因為存在斷層的問題,那麼最好的方法就是const的值

      永遠也不要變,這樣就可以避免問題的發生,既然是永遠都不變的東西,當然是跟著“型別”走比跟著“例項”走要好的多,你說

      對不對,因為static是個小快取,沒必要new一下才產生。。。

 

Q: readonly欄位只能在ctor中初始化嗎?

 

 

A:這個問題蠻有意思的,我們知道readonly的意思就是隻讀欄位的意思,我們知道一般的欄位具有可讀寫的功能,

     先還是看看編譯器怎麼說。

 

  從編譯器上可以看到,確實readonly的初始化還可以在“變數初始化”的時候進行初始化,那麼這樣說Question的答案

應該就是否定的,但是真的是如此嗎?我們都知道有一個東西叫做“語法糖”,而且經常是編譯器提供給我們用的,所以

真正的想看到發生了什麼,只能用ILDasm.exe 穿透編譯器,看看到底發生了什麼。

 

從IL中可以看到,真的就是編譯器的語法糖,本質上都是在ctor中初始化的,所以說,看問題千萬不要看表面。

 

注:Stsfld 用來自計算堆疊的值替換靜態欄位的值。

相關文章