麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

C#基本知識點(diǎn)-Readonly和Const的區(qū)別

2019-11-17 02:38:25
字體:
供稿:網(wǎng)友

C#基本知識點(diǎn)-Readonly和Const的區(qū)別

C#基本知識點(diǎn)-Readonly和Const的區(qū)別

什么是靜態(tài)常量(Const)和動(dòng)態(tài)常量(Readonly)

先解釋下什么是靜態(tài)常量(Const)以及什么是動(dòng)態(tài)常量(Readonly)。

靜態(tài)常量(Const)是指編譯器在編譯時(shí)候會(huì)對常量進(jìn)行解析,并將常量的值替換成初始化的那個(gè)值。

動(dòng)態(tài)常量(Readonly)的值則是在運(yùn)行的那一刻才獲得的,編譯器編譯期間將其標(biāo)示為只讀常量,而不用常量的值代替,這樣動(dòng)態(tài)常量不必在聲明的時(shí)候就初始化,而可以延遲到構(gòu)造函數(shù)中初始化。

靜態(tài)常量(Const)和動(dòng)態(tài)常量(Readonly)之間的區(qū)別

靜態(tài)常量(Compile-timeConstant)

動(dòng)態(tài)常量(RuntimeConstant)

定義

聲明的同時(shí)要設(shè)置常量值。

聲明的時(shí)候可以不需要進(jìn)行設(shè)置常量值,可以在類的構(gòu)造函數(shù)中進(jìn)行設(shè)置。

類型限制

只能修飾基元類型,枚舉類型或者字符串類型。

沒有限制,可以用它定義任何類型的常量。

對于類對象而言

對于所有類的對象而言,常量的值是一樣的。

對于類的不同對象而言,常量的值可以是不一樣的。

內(nèi)存消耗

無。

要分配內(nèi)存,保存常量實(shí)體。

綜述

性能要略高,無內(nèi)存開銷,但是限制頗多,不靈活。

靈活,方便,但是性能略低,且有內(nèi)存開銷。

Const修飾的常量在聲明的時(shí)候必須初始化;Readonly修飾的常量則可以延遲到構(gòu)造函數(shù)初始化。

Const常量既可以聲明在類中也可以在函數(shù)體內(nèi),但是StaticReadonly常量只能聲明在類中。Const是靜態(tài)常量,所以它本身就是Static的,因此不能手動(dòng)再為Const增加一個(gè)Static修飾符。

Const修飾的常量在編譯期間就被解析,即:經(jīng)過編譯器編譯后,我們都在代碼中引用Const變量的地方會(huì)用Const變量所對應(yīng)的實(shí)際值來代替;Readonly修飾的常量則延遲到運(yùn)行的時(shí)候。

舉個(gè)例子來說明一下:

publicstaticreadonlyintNumberA=NumberB*10;

publicstaticreadonlyintNumberB=10;

publicconstintNumberC=NumberD*10;

publicconstintNumberD=10;

staticvoidMain(string[]args)

{

Console.WriteLine("NumberAis{0},NumberBis{1}.",NumberA,NumberB);//NumberAis0,NumberBis10.

Console.WriteLine("NumberCis{0},NumberDis{1}.",NumberC,NumberD);//NumberCis100,NumberDis10.

Console.ReadKey();

}

以上是語法方面的應(yīng)用,那在實(shí)際的用法上,還是有些微妙的變化,通常不易發(fā)覺.

舉個(gè)例子來說明一下:

在程序集DoTestConst.dll中有一個(gè)類MyClass,定義了一個(gè)公開的靜態(tài)變量Count

publicstaticclassMyClass

{

publicconstintCount=10;

}

然后另外一個(gè)應(yīng)用程序中引用DoTestConst.dll,并在代碼中作如下調(diào)用:

publicstaticvoidMain(string[]args)

{

Console.WriteLine(DoTestConst.MyClass.Count);//輸出10

Console.ReadKey();

}

毫無疑問,非常簡單的代碼,直接輸出10。

接下來更新MyClass的Count的值為20,然后重新編譯DoTestConst.dll,并更新到應(yīng)用程序的所在目錄中,注意不要編譯應(yīng)用程序。那么這時(shí)候的輸出結(jié)果按預(yù)期那么想應(yīng)該是20才對,但實(shí)際上還是10,為什么呢?

這就是Const的特別之處,有多特別還是直接看生成的IL,查看IL代碼(假設(shè)這時(shí)候Count的值為10)

IL_0000:nop

IL_0001:ldc.i4.s10

IL_0003:callvoid[mscorlib]System.Console::WriteLine(int32)

紅色代碼很明顯的表明了,直接加載10,沒有通過任何類型的加載然后得到對應(yīng)變量的,也就是說在運(yùn)行時(shí)沒有去加載DoTestConst.dll,那么是否意味著沒有DoTestConst.dll也可以運(yùn)行呢?答案是肯定的,刪除DoTestConst.dll也可以運(yùn)行,是否很詭異呢?也就解釋了之前的實(shí)驗(yàn),為什么更新Const變量的值之后沒有調(diào)用新的值,因?yàn)槌绦蛟谶\(yùn)行的時(shí)候根本不會(huì)去加載DoTestConst.dll。那么10這個(gè)值是從哪來的呢?實(shí)際上CLR對于Const變量做了特殊處理,是將Const的值直接嵌入在生成的IL代碼中,在執(zhí)行的時(shí)候不會(huì)再去從dll加載。這也帶來了一個(gè)不容易發(fā)覺的Bug,因此在引用其他程序集的Const變量時(shí),需考慮到版本更新問題,要解決這個(gè)問題就是把調(diào)用的應(yīng)用程序再編譯一次就ok了。但實(shí)際程序部署更新時(shí)可能只更新個(gè)別文件,這時(shí)候就必須用Readonly關(guān)鍵字來解決這個(gè)問題。

接下來看Readonly的版本:

publicstaticclassMyClass

{

publicstaticreadonlyintCount=10;

}

調(diào)用方代碼不變,接著看生成的IL代碼:

IL_0000:nop

IL_0001:ldsfldint32[DoTestConst]DoTestConst.MyClass::Count

IL_0006:callvoid[mscorlib]System.Console::WriteLine(int32)

很明顯加載代碼變了,一個(gè)很常見的ldsfld動(dòng)作,請求了DoTestConst.MyClass的Count變量,是通過強(qiáng)制要求加載DoTestConst來實(shí)現(xiàn)的。因此這時(shí)候更新Count的值重新編譯之后,還是不編譯調(diào)用程序,然后再執(zhí)行就會(huì)看到新的值。而這時(shí)候如果刪除DoTestConst.dll那么,會(huì)出現(xiàn)找不到dll之類的異常。這也充分說明了對于Readonly定義的變量是在運(yùn)行時(shí)加載的。

動(dòng)態(tài)常量(Readonly)被賦值后不可以改變

ReadOnly變量是運(yùn)行時(shí)變量,它在運(yùn)行時(shí)第一次賦值后將不可以改變。其中“不可以改變”分為兩層意思:

對于值類型變量,值本身不可以改變(Readonly,只讀)

對于引用類型變量,引用本身(相當(dāng)于指針)不可改變。

值類型變量,舉個(gè)例子說明一下:

publicclassStudent

{

publicreadonlyintAge;

publicStudent(intage)

{

this.Age=age;

}

}

Student的實(shí)例Age在構(gòu)造函數(shù)中被賦值以后就不可以改變,下面的代碼不會(huì)編譯通過:

Studentstudent=newStudent(20);

student.Age=21;//錯(cuò)誤信息:無法對只讀的字段賦值(構(gòu)造函數(shù)或變量初始化器中除外)

引用類型變量,舉個(gè)例子說明一下:

publicclassStudent

{

publicintAge;//注意這里的Age是沒有readonly修飾符的

publicStudent(intage)

{

this.Age=age;

}

}

publicclassSchool

{

publicreadonlyStudentStudent;

publicSchool(Studentstudent)

{

this.Student=student;

}

}

School實(shí)例的Student是一個(gè)引用類型的變量,賦值后,變量不能再指向其他任何的Student實(shí)例,所以,下面的代碼將不會(huì)編譯通過:

Schoolschool=newSchool(newStudent(10));

school.Student=newStudent(20);//錯(cuò)誤信息:無法對只讀的字段賦值(構(gòu)造函數(shù)或變量初始化器中除外)

引用本身不可以改變,但是引用說指向的實(shí)例的值是可以改變的。所以下面的代碼是可以編譯通過的:

Schoolschool=newSchool(newStudent(10));

school.Student.Age=20;

在構(gòu)造方法中,我們可以多次對Readonly修飾的常量賦值。舉個(gè)例子說明一下:

publicclassStudent

{

publicreadonlyintAge=20;//注意:初始化器實(shí)際上是構(gòu)造方法的一部分,它其實(shí)是一個(gè)語法糖

publicStudent(intage)

{

this.Age=age;

this.Age=25;

this.Age=30;

}

}

總結(jié)

Const和Readonly的最大區(qū)別(除語法外)

Const的變量是嵌入在IL代碼中,編譯時(shí)就加載好,不依賴外部dll(這也是為什么不能在構(gòu)造方法中賦值)。Const在程序集更新時(shí)容易產(chǎn)生版本不一致的情況。

Readonly的變量是在運(yùn)行時(shí)加載,需請求加載dll,每次都獲取最新的值。Readonly賦值引用類型以后,引用本身不可以改變,但是引用所指向的實(shí)例的值是可以改變的。在構(gòu)造方法中,我們可以多次對Readonly賦值。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 天天色综合2 | 特级毛片免费视频 | 一级外国毛片 | 精品久久久久久久久久久久 | 国产在线精品91 | 蜜桃91丨九色丨蝌蚪91桃色 | 国产精品久久久久久久久久尿 | 国产 一区 | 国产又白又嫩又紧又爽18p | 中文字幕四区 | 在线观看美女av | 日本欧美一区二区三区在线播 | 国产精品久久久久久久不卡 | 精品在线视频播放 | 国产亚洲综合精品 | 欧美成人一区二区三区 | 成片免费观看大全 | 美国av免费看 | 欧美一级黄 | 国产成人小视频在线观看 | 中文字幕网站在线 | 99爱视频在线| 免费看成年人视频在线 | 日本黄色一级毛片 | 日韩精品中文字幕在线播放 | 欧美一级成人 | 亚洲天堂成人在线观看 | 高清国产免费 | 久久人添人人爽人人爽人人片av | 伦一区二区三区中文字幕v亚洲 | 九九热在线视频观看这里只有精品 | 久久久久久久久久久国产精品 | 99在线在线视频免费视频观看 | 色悠悠久久久久 | 日本人乱人乱亲乱色视频观看 | 久久精品亚洲精品国产欧美kt∨ | 毛片在线播放视频 | 一本色道久久综合亚洲精品图片 | h视频在线播放 | 午夜激情视频网站 | 99亚洲伊人久久精品影院红桃 |