C 基本知識點 Readonly和Const的區別

2022-09-02 22:54:25 字數 4600 閱讀 7621

c#基本知識點-readonly和const的區別

什麼是靜態常量(const)和動態常量(readonly)

先解釋下什麼是靜態常量(const)以及什麼是動態常量(readonly)。

靜態常量(const)是指編譯器在編譯時候會對常量進行解析,並將常量的值替換成初始化的那個值。

動態常量(readonly)的值則是在執行的那一刻才獲得的,編譯器編譯期間將其標示為唯讀常量,而不用常量的值代替,這樣動態常量不必在宣告的時候就初始化,而可以延遲到建構函式中初始化。

靜態常量(const)和動態常量(readonly)之間的區別

靜態常量(compile-time constant)

動態常量(runtime constant)

定義宣告的同時要設定常量值。

宣告的時候可以不需要進行設定常量值,可以在類的建構函式中進行設定。

型別限制

只能修飾基元型別,列舉型別或者字串型別。

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

對於類物件而言

對於所有類的物件而言,常量的值是一樣的。

對於類的不同物件而言,常量的值可以是不一樣的。

記憶體消耗

無。要分配記憶體,儲存常量實體。

綜述效能要略高,無記憶體開銷,但是限制頗多,不靈活。

靈活,方便,但是效能略低,且有記憶體開銷。

const修飾的常量在宣告的時候必須初始化;readonly修飾的常量則可以延遲到建構函式初始化 。

const常量既可以宣告在類中也可以在函式體內,但是static readonly常量只能宣告在類中。const是靜態常量,所以它本身就是static的,因此不能手動再為const增加乙個static修飾符。

const修飾的常量在編譯期間就被解析,即:經過編譯器編譯後,我們都在**中引用const變數的地方會用const變數所對應的實際值來代替; readonly修飾的常量則延遲到執行的時候。

舉個例子來說明一下:

public static readonly int numbera = numberb * 10;

public static readonly int numberb = 10;

public const int numberc = numberd*10;

public const int numberd = 10;

static void main(string args)

console.writeline("numbera is , numberb is .", numbera, numberb);//numbera is 0, numberb is 10.

console.writeline("numberc is , numberd is .", numberc, numberd);//numberc is 100, numberd is 10.

console.readkey();

以上是語法方面的應用,那在實際的用法上,還是有些微妙的變化,通常不易發覺.

舉個例子來說明一下:

在程式集dotestconst.dll 中有乙個類myclass,定義了乙個公開的靜態變數count

public static class myclass

public const int count = 10;

然後另外乙個應用程式中引用dotestconst.dll,並在**中作如下呼叫:

public static void main(string args)

console.writeline(dotestconst.myclass.count);//輸出10

console.readkey();

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

接下來更新myclass的count的值為20,然後重新編譯dotestconst.dll,並更新到應用程式的所在目錄中,注意不要編譯應用程式。那麼這時候的輸出結果按預期那麼想應該是20才對,但實際上還是10,為什麼呢?

這就是const的特別之處,有多特別還是直接看生成的il,檢視il**(假設這時候count的值為10)

il_0000: nop

il_0001: ldc.i4.s 10

il_0003: call void [mscorlib]system.console::writeline(int32)

紅色**很明顯的表明了,直接載入10,沒有通過任何型別的載入然後得到對應變數的,也就是說在執行時沒有去載入dotestconst.dll,那麼是否意味著沒有dotestconst.dll也可以執行呢?答案是肯定的,刪除dotestconst.dll也可以執行,是否很詭異呢?也就解釋了之前的實驗,為什麼更新const變數的值之後沒有呼叫新的值,因為程式在執行的時候根本不會去載入dotestconst.dll。那麼10這個值是從哪來的呢?實際上clr對於const變數做了特殊處理,是將const的值直接嵌入在生成的il**中,在執行的時候不會再去從dll載入。這也帶來了乙個不容易發覺的bug,因此在引用其他程式集的const變數時,需考慮到版本更新問題,要解決這個問題就是把呼叫的應用程式再編譯一次就ok了。但實際程式部署更新時可能只更新個別檔案,這時候就必須用readonly關鍵字來解決這個問題。

接下來看readonly的版本:

public static class myclass

public static readonly int count = 10;

呼叫方**不變,接著看生成的il**:

il_0000: nop

il_0001: ldsfld int32 [dotestconst]dotestconst.myclass::count

il_0006: call void [mscorlib]system.console::writeline(int32)

很明顯載入**變了,乙個很常見的ldsfld動作,請求了dotestconst.myclass的count變數,是通過強制要求載入dotestconst來實現的。因此這時候更新count的值重新編譯之後,還是不編譯呼叫程式,然後再執行就會看到新的值。而這時候如果刪除dotestconst.dll那麼,會出現找不到dll之類的異常。這也充分說明了對於readonly定義的變數是在執行時載入的。

動態常量(readonly)被賦值後不可以改變

readonly 變數是執行時變數,它在執行時第一次賦值後將不可以改變。其中「不可以改變」分為兩層意思:

對於值型別變數,值本身不可以改變(readonly, 唯讀)

對於引用型別變數,引用本身(相當於指標)不可改變。

值型別變數,舉個例子說明一下:

public class student

public readonly int age;

public student(int age)

this.age = age;

student的例項age在建構函式中被賦值以後就不可以改變,下面的**不會編譯通過:

student student = new student(20);

student.age = 21; //錯誤資訊:無法對唯讀的字段賦值(建構函式或變數初始化器中除外)

引用型別變數,舉個例子說明一下:

public class student

public int age; //注意這裡的age是沒有readonly修飾符的

public student(int age)

this.age = age;

public class school

public readonly student student;

public school(student student)

this.student = student;

school例項的student是乙個引用型別的變數,賦值後,變數不能再指向其他任何的student例項,所以,下面的**將不會編譯通過:

school school = new school(new student(10));

school.student = new student(20);//錯誤資訊:無法對唯讀的字段賦值(建構函式或變數初始化器中除外)

引用本身不可以改變,但是引用說指向的例項的值是可以改變的。所以下面的**是可以編譯通過的:

school school = new school(new student(10));

school.student.age = 20;

在構造方法中,我們可以多次對readonly修飾的常量賦值。舉個例子說明一下:

public class student

public readonly int age = 20;//注意:初始化器實際上是構造方法的一部分,它其實是乙個語法糖

public student(int age)

this.age = age;

this.age = 25;

this.age = 30;

總結const和readonly的最大區別(除語法外)

const的變數是嵌入在il**中,編譯時就載入好,不依賴外部dll(這也是為什麼不能在構造方法中賦值)。const在程式集更新時容易產生版本不一致的情況。

readonly的變數是在執行時載入,需請求載入dll,每次都獲取最新的值。readonly賦值引用型別以後,引用本身不可以改變,但是引用所指向的例項的值是可以改變的。在構造方法中,我們可以多次對readonly賦值。

C 基本知識點 Readonly和Const的區別

什麼是靜態常量 const 和動態常量 readonly 先解釋下什麼是靜態常量 const 以及什麼是動態常量 readonly 靜態常量 const 是指編譯器在編譯時候會對常量進行解析,並將常量的值替換成初始化的那個值。動態常量 readonly 的值則是在執行的那一刻才獲得的,編譯器編譯期間...

C 基本知識點

繼承 語法 class 子類 繼承方式 父類 如果子類 現和父類同名的成員函式,子類中的同名成員會隱藏掉父類中所有同名成員函式,如果想訪問父類中被隱藏的同名成員函式,需要加作用域。動態多型滿足條件 1 有繼承關係 2 子類重寫父類的虛函式 動態多型使用 父類的指標或者引用 執行子類物件 includ...

基本知識點

1 程序和執行緒的關係 1 在有執行緒的作業系統裡面,程序是分配資源的基本單位,執行緒是排程的基本單位。2 1個程序可以擁有多個執行緒 3 執行緒同時也有一些自己的資源,包括 程式計數器,堆疊等 4 因為執行緒所擁有的資源比較少,因此進行排程的時候所消耗的資源就少。5 執行緒共享程序的 段,程序的一...