gpt4 book ai didi

c# - 说明引用字符串的 IL 生成代码

转载 作者:行者123 更新时间:2023-11-30 22:57:17 24 4
gpt4 key购买 nike

我今天正在执行一些重构,我注意到一件我无法理解的奇怪事情......或者更好的是部分同意我在网上找到的内容,但仍有一些问题。

请考虑这个简单的例子

 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 代码(通过 IL 浏览器从 resharp 获取)

我看到下面的代码

.method private hidebysig static void 
Main(
string[] args
) cil managed
{
.entrypoint
.maxstack 8

// [16 13 - 16 34]
IL_0000: ldsfld string ConsoleApp4.Program::a
IL_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 8

IL_0000: ldarg.0 // this
IL_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::a
IL_000a: ret

} // end of method Program::.cctor
} // end of class ConsoleApp4.Program

关于静态字符串,它的行为与我预期的一样。相反,对于 const,它在堆栈上加载了一个新值...事实上,查看 ldstr 操作码 here它说

Pushes a new object reference to a string literal stored in the metadata

我读过 here那个

Now, wherever myInt is referenced in the code, instead of having to do a "ldloc.0" to get the value from the variable, the MSIL just loads the constant value which is hardcoded into the MSIL. As such, there's usually a small performance and memory advantage to using constants.However, in order to use them you must have the value of the variable at compile time, and any references to this constant at compile time, even if they're in a different assembly, will have this substitution made.

如果您在编译时知道常量的值,那么常量肯定是一个有用的工具。如果你不这样做,但又想确保你的变量只被设置一次,你可以在C#中使用readonly关键字(它映射到MSIL中的initonly)来表明变量的值只能在构造函数中设置;在那之后,更改它是错误的。这通常在字段有助于确定类的身份时使用,并且通常设置为等于构造函数参数。

但我为什么要体验更好的性能呢? (即使考虑到它很容易理解)?内存占用情况如何?

提前致谢

最佳答案

考虑这段代码:

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)。

关于c# - 说明引用字符串的 IL 生成代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53767383/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com