我正在使用ILSpy反编译.Net的程序集并查看代码。当我在WindowsBase.dll
中浏览System.Windows.Vector.AngleBetween(Vector, Vector)
的代码时,我偶然发现了一些奇怪的东西。
以下是该函数的完整代码:
public static double AngleBetween(Vector vector1, Vector vector2)
{
double y = vector1._x * vector2._y - vector2._x * vector1._y;
double x = vector1._x * vector2._x + vector1._y * vector2._y;
return Math.Atan2(y, x) * (180.0 / Math.PI);
}
显然ILSpy可以识别Math.PI
,它是一个常量。
关于C#中的常量,Microsoft Docs是这样说的:
事实上,当编译器在C#源代码中遇到常量标识符时,它会将文字值直接替换到它生成的中间语言(IL)代码中。
基于这一点,ILSpy所做的似乎是不可能的。
注意:即使在设置中取消选中“使用调试符号中的变量名(如果可用)”和“显示调试符号中的信息(如果可用)”选项,也会出现此行为。
发布于 2019-04-11 02:34:40
正如您在此ILSpy issue和相应的pull request中所看到的,这是专门为熟知的值实现(硬编码)的,比如Math.PI
。
在GitHub问题上:
我想用下面的方法来计算π系数:c = Math.PI / constant
。如果我们得到“好”值(恰好等于1.0、2.0、0.5、1/180等),我们只需将其替换为符号表达式(Math.PI、Math.PI * 2、Math.PI / 2、Math.PI / 180等)。
发布于 2019-04-11 02:27:11
在LINQPad中的快速测试显示了所生成的IL代码(从here复制的PI常量)中的一些差异。
来源:
void Main()
{
double a = Math.PI;
double b = 3.14159265358979;
}
IL:
IL_0000: nop
IL_0001: ldc.r8 18 2D 44 54 FB 21 09 40
IL_000A: stloc.0 // a
IL_000B: ldc.r8 11 2D 44 54 FB 21 09 40
IL_0014: stloc.1 // b
IL_0015: ret
在常量和文字值之间生成的IL代码似乎确实有细微的区别,但我还不确定它到底是什么意思。
来自MSDN documentation的上述值似乎与来自.NET Reference Source的信息相矛盾(请参阅注释)。从源代码中调整代码后,IL是相同的。
来源:
void Main()
{
var a = Math.PI;
var b = 3.14159265358979323846;
}
IL:
IL_0000: nop
IL_0001: ldc.r8 18 2D 44 54 FB 21 09 40
IL_000A: stloc.0 // a
IL_000B: ldc.r8 18 2D 44 54 FB 21 09 40
IL_0014: stloc.1 // b
IL_0015: ret
顺便说一句,似乎有一个open issue可以解决文档/源代码不一致的问题。
https://stackoverflow.com/questions/55618930
复制相似问题