深入探討C#中的const、readonly關(guān)鍵字
首先不可否認(rèn),這些在面試上會(huì)經(jīng)常被面試官問(wèn)起,但是你回答的讓面試官滿意嗎?當(dāng)然如果你知道了這些原理,或許你就不
怕了。既然說(shuō)到了原理,我們還是從MSDN說(shuō)起。
一:值得推敲的幾個(gè)地方
1.先來(lái)看看msdn上面對(duì)const是怎么說(shuō)的,我們會(huì)看到。不能修改,編譯時(shí)常量這些關(guān)鍵性信息。
Q: const為什么不能被修改。
A:這個(gè)很簡(jiǎn)單,很多教科書上面都說(shuō),當(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)行起來(lái)。
既然我把mainproject跑起來(lái)了,并且也引用了Test.dll,剛才也說(shuō)了,編譯的時(shí)候會(huì)把常量值保存在程序集的元數(shù)據(jù)中,那我們
就找一找,打開(kāi)ILdasm.exe,并且Ctrl+M。
很可惜,我并沒(méi)有找到Ctrip的符號(hào),也沒(méi)有找到int.MaxValue,也沒(méi)有找到所謂的0x7fffffff,倒是找到了一個(gè)Assembly的一些版本信息的元數(shù)據(jù),那么這時(shí)候你可能會(huì)疑惑了,究竟const的值有沒(méi)有保存到Assembly里面去呢?很簡(jiǎn)單的一個(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)一步佐證了剛才的說(shuō)法,const確確實(shí)實(shí)是保存在Assembly的元數(shù)據(jù)中,這里還要順便提示一下,Enum本質(zhì)上是const,所以它也存在我剛才說(shuō)的斷層的問(wèn)題,說(shuō)到這里,我想你對(duì)const的原理應(yīng)該比較熟悉了,現(xiàn)在我們來(lái)看看Question的問(wèn)題。既然是元數(shù)據(jù),那什么是元數(shù)據(jù)?“描述數(shù)據(jù)的數(shù)據(jù)” 叫做元數(shù)據(jù),既然它是基礎(chǔ)的描述性數(shù)據(jù),那么在定義好后是決對(duì)不能改變的,這個(gè)定義時(shí)也就是msdn說(shuō)的編譯時(shí),是不是so easy呢?
Q: const為什么要做成靜態(tài)的,而不是做成實(shí)例的
A: 其實(shí)通過(guò)對(duì)第一個(gè)Question的分析,很多東西我們應(yīng)該都會(huì)豁然開(kāi)朗,因?yàn)榇嬖跀鄬拥膯?wèn)題,那么最好的方法就是const的值
永遠(yuǎn)也不要變,這樣就可以避免問(wèn)題的發(fā)生,既然是永遠(yuǎn)都不變的東西,當(dāng)然是跟著“類型”走比跟著“實(shí)例”走要好的多,你說(shuō)對(duì)不對(duì),因?yàn)閟tatic是個(gè)小緩存,沒(méi)必要new一下才產(chǎn)生。。。
Q: readonly字段只能在ctor中初始化嗎?
A:這個(gè)問(wèn)題蠻有意思的,我們知道readonly的意思就是只讀字段的意思,我們知道一般的字段具有可讀寫的功能,
先還是看看編譯器怎么說(shuō)。
從編譯器上可以看到,確實(shí)readonly的初始化還可以在“變量初始化”的時(shí)候進(jìn)行初始化,那么這樣說(shuō)Question的答案應(yīng)該就是否定的,但是真的是如此嗎?我們都知道有一個(gè)東西叫做“語(yǔ)法糖”,而且經(jīng)常是編譯器提供給我們用的,所以真正的想看到發(fā)生了什么,只能用ILDasm.exe 穿透編譯器,看看到底發(fā)生了什么。
從IL中可以看到,真的就是編譯器的語(yǔ)法糖,本質(zhì)上都是在ctor中初始化的,所以說(shuō),看問(wèn)題千萬(wàn)不要看表面。
注:Stsfld 用來(lái)自計(jì)算堆棧的值替換靜態(tài)字段的值。
相關(guān)文章
基于C#實(shí)現(xiàn)一個(gè)溫濕度監(jiān)測(cè)小工具
這篇文章主要為大家詳細(xì)介紹了如何基于C#實(shí)現(xiàn)一個(gè)溫濕度監(jiān)測(cè)小工具,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-01-01詳解C# 泛型中的數(shù)據(jù)類型判定與轉(zhuǎn)換
這篇文章主要介紹了C# 泛型中的數(shù)據(jù)類型判定與轉(zhuǎn)換,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07深入理解C# abstract和virtual關(guān)鍵字
深入理解C# abstract和virtual關(guān)鍵字,學(xué)習(xí)c#的朋友可以參考下。2011-06-06C#連接SQL?Sever數(shù)據(jù)庫(kù)詳細(xì)圖文教程
C#是Microsoft公司為.NET Framework推出的重量級(jí)語(yǔ)言,和它搭配最完美的數(shù)據(jù)庫(kù)無(wú)疑就是Microsoft SQL Server了,下面這篇文章主要給大家介紹了關(guān)于C#連接SQL?Sever數(shù)據(jù)庫(kù)的詳細(xì)圖文教程,需要的朋友可以參考下2023-06-06insert語(yǔ)句太長(zhǎng)用StringBuilder優(yōu)化一下
insert語(yǔ)句太長(zhǎng)用StringBuilder優(yōu)化一下,下面是示例代碼,需要的朋友可以研究研究2014-07-07C#實(shí)現(xiàn)漢字轉(zhuǎn)漢語(yǔ)拼音的示例代碼
這篇文章主要介紹了如何利用C#實(shí)現(xiàn)漢字轉(zhuǎn)漢語(yǔ)拼音,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定幫助,感興趣的小伙伴可以跟隨小編一起動(dòng)手試一試2022-03-03C#多線程開(kāi)發(fā)之任務(wù)并行庫(kù)詳解
最近在學(xué)習(xí)C#的并行編程,在每本書上的看到的知識(shí)點(diǎn)都不全面,所以先參考多本書書籍的講解,將并行編程,多線程編程的知識(shí)點(diǎn)整理一下,這篇文章主要給大家介紹了關(guān)于C#多線程開(kāi)發(fā)之任務(wù)并行庫(kù)的相關(guān)資料,需要的朋友可以參考下2021-09-09