巧用 readonly與 const

c# 中的常量有兩種,分別是編譯期常量和運行期常量。通過名字我們就可以看出來它倆在行爲上是不同的。在開發中如果這兩種常量選擇的不合適,就會影響到程序的開發工作以及程序的性能。下面我們先來看一下運行期常量和編譯期常量的定義方法。

零、定義

運行期常量我們使用 readonly 來定義,而編譯器常量我們使用 const 來定義。

// 運行期常量
public static readonly string name = "張三" ;
//編譯期常量
public const int age = 20 ;

一、運行期常量和編譯期常量

  1. 編譯期常量
    編譯期常量可以使程序運行速度變得快一些,但是它沒有運行期常量靈活,一般我們會在特別關注程序性能,並且常量取值不會隨版本的變化而變化的情況下才會使用到它。這種常量與直接使用字面量的寫法在編譯爲 MSIL 後的結果是一樣的。例如 if( userAge == age )等價於 if( userAge == 20 )
    這裏有幾點很重要的需要注意:
  • 編譯期常量只能用內置的整數、浮點數、枚舉、字符串或 null 來進行初始化和賦值,在生成 MSIL 的過程中只有這些原始類型的編譯期常量纔會被替換成字面量;
  • 編譯期常量可以在方法內部聲明;
  • 編譯期常量是靜態常量;
  • 在另一個程序集中調用靜態常量會導致不兼容問題(這個問題將在案例小節中講解)。
  1. 運行期常量
    在開發的大部分情況下我們使用的是運行期常量,這種常量靈活性強,幾乎可以支持所有的類型。它不僅可以在聲明的時候直接初始化,也可以在構造器中初始化。運行期常量所生成的 MSIL 會通過引用的方式來使用這個常量。
    同樣這裏有幾點需要注意:
  • 運行期常量可以用來聲明實例級別的常量,給同一個實例設定不同的常量值;
  • 運行期常量是在程序運行時纔會被解析。

二、案例

下面我們來看一個案例:

namespace readonly_and_const
{
    public class main
    {
        public static readonly string name = "張三";
        public const int age = 20;
    }
}

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(readonly_and_const.main.age);
            Console.WriteLine(readonly_and_const.main.name);
            Console.Read();
        }
    }
}

上述代碼中我們創建了兩個程序集,Test 程序集引用了 readonly_and_const 程序集。我們先行一下代碼,來看一下運行結果:
在這裏插入圖片描述
下面我們將程序集 readonly_and_const 中的 age 和 name 都進行修改並運行:

namespace readonly_and_const
{
    public class main
    {
        public static readonly string name = "jack";
        public const int age = 25;
    }
}

運行結果如下:
在這裏插入圖片描述
我們從運行結果可以看到,name 的值已經改變,但是 age 的值沒有改變,這是因爲在編譯 Test 程序集時編譯器直接寫入了 20 這個字面量,而不是去引用放置 age 的那個空間。但是 name 因爲時運行期常量,因此會在運行時去應用放置了 name 的那個空間,因此輸出了正確的值。解決這個問題有兩種方法,一種是將 age 修改爲運行期常量,另一種是重新編譯 Test 程序集。具體應該使用哪個方法解決,應該視程序而定。

Tip:修改訪問級別爲 public 的 const 常量時調用它的程序集必須重新編譯,因爲這種修改相當於修改接口。但是修改 public 級別的 readonly 常量相當於修改細節實現,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章