我今天正在執行一些重構,我注意到一件我無法理解的奇怪事情......或者更好的是,我部分同意我在網上找到的內容,但仍有一些問題。請考慮這個簡單的例子 class Program{ public static readonly string a = "a"; public const string b = "b"; static void Main(string[] args) { Console.WriteLine(a); Console.WriteLine(b); }}現在,如果我查看生成的 IL 代碼(通過來自 resharp 的 IL 瀏覽器獲得)我看到以下代碼.method private hidebysig static void Main( string[] args) cil managed { .entrypoint.maxstack 8// [16 13 - 16 34]IL_0000: ldsfld string ConsoleApp4.Program::aIL_0005: call void [mscorlib]System.Console::WriteLine(string)// [18 13 - 18 34]IL_000a: ldstr "b"IL_000f: call void [mscorlib]System.Console::WriteLine(string)// [19 9 - 19 10]IL_0014: ret } // end of method Program::Main .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8IL_0000: ldarg.0 // thisIL_0001: call instance void [mscorlib]System.Object::.ctor()IL_0006: ret } // end of method Program::.ctor .method private hidebysig static specialname rtspecialname void .cctor() cil managed {.maxstack 8// [11 9 - 11 47]IL_0000: ldstr "a"IL_0005: stsfld string ConsoleApp4.Program::aIL_000a: ret } // end of method Program::.cctor } // end of class ConsoleApp4.Program對于靜態字符串,它的行為符合我的預期。而不是 const 它在堆棧上加載了一個新值......事實上,它在這里查看 ldstr 操作碼將新對象引用推送到存儲在元數據中的字符串文字我在這里讀過現在,無論在代碼中何處引用 myInt,MSIL 都無需執行“ldloc.0”來從變量中獲取值,而是將硬編碼到 MSIL 中的常量值加載。因此,使用常量通常具有較小的性能和內存優勢。但是,為了使用它們,您必須在編譯時獲得變量的值,以及在編譯時對該常量的任何引用,即使它們在一個不同的組件,將進行此替換。如果您知道編譯時的值,常量肯定是一個有用的工具。如果你不這樣做,但想確保你的變量只設置一次,你可以使用 C# 中的 readonly 關鍵字(在 MSIL 中映射為 initonly)來指示變量的值只能在構造函數中設置;之后,更改它是錯誤的。這通常在字段有助于確定類的身份時使用,并且通常設置為等于構造函數參數。但是我為什么要體驗更好的性能呢?(即使考慮到它是相當可追溯的)?內存占用呢?
1 回答

茅侃侃
TA貢獻1842條經驗 獲得超22個贊
考慮這段代碼:
public class Program
{
public const int ConstField1 = 1;
public const int ConstField2 = 2;
public const int ConstField3 = 3;
public const int ConstField4 = 4;
}
這四個 const int32 數字僅存儲在與程序集元數據對應的內存中(因此可以通過反射獲得),而不會存儲在實際的運行時類型信息中。與 相比static readonly,這節省了 16 個字節的內存。在字符串的情況下,運行時也不必在實際用于其他代碼之前分配字符串(因為ldstr不用于初始化字段)。您可能會爭辯說這并沒有節省多少,但考慮一下枚舉 - 它們基本上是具有大量 const 字段的靜態類型。
性能改進也很明顯——因為不需要每次使用時都獲取值,內存碎片減少了,并且可以對否則不可能的值執行其他優化(例如簡化表達式,如BindingFlags.NonPublic | BindingFlags.Instance) . 此外,不需要調用靜態構造函數,因此這是另一點(盡管在某些情況下可能不會調用它,請參閱 參考資料beforefieldinit)。
- 1 回答
- 0 關注
- 142 瀏覽
添加回答
舉報
0/150
提交
取消