假设我们在编译的程序集中有一些常量。让我们举一个例子来说明Math from类mscorlib.dll和常量Math.PI
如果以-code的形式查看源码IL,那么我们会看到如下的字段声明:
.field public static literal float64 PI = float64(3.1415926535897931)
也就是说,实际上,它PI是一个标记为文字的公共静态字段
。正是因为后者,ldsfld关于Math.PI
因此,以下代码将不起作用:
.method public static float64 GetPi() cil managed
{
.maxstack 1
ldsfld float64 [mscorlib]System.Math::PI
ret
}
当被调用时GetPi(),我们会得到一个运行时错误:
System.MissingFieldException:“找不到字段:'System.Math.PI'。”
在这方面,我有一个问题:是否可以通过一般手段从程序集中提取文字的值CIL,如果可以,如何做到这一点?
PS - 我非常清楚,当IL从指令创建 -code 时,例如C#常量值会立即被替换,所以:
return a * Math.PI;
将转换为:
ldloc a
ldc.r8 3.1415926535897931
mul
ret
但是,是否有一条CIL指令仍然可以提取常量字段的值仍然很有趣
CIL规范非常明确地指出:
精选作品
所以不,CIL 中没有这样的指令。
但是,如同一段所述:
翻译CIL 问题的答案 - 如何使用公共静态文字字段?
添加到@Grundy的答案 :
如前所述,不可能
CIL通过常规方式获取文字的值,因此您应该使用反射实际上,这就是我们要做的)
结果是这样的
generic方法:然后方法
GetPi()可以改写成这样:现在方法调用不会落入
runtime,而是会返回预期值System.Math.PI)我再次强调,常量就是常量,它们的不可变值会立即替换到
IL-code 中,因此在编写某种编译器时,您不应该使用上面的代码,而应该简单地手动将所需的值写入其中应该此答案仅用于教育目的)