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

來源:互聯網
上載者:User

標籤:

什麼是靜態常量(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 {0}, NumberB is {1}.", NumberA, NumberB);//NumberA is 0, NumberB is 10.            Console.WriteLine("NumberC is {0}, NumberD is {1}.", 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的區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.