3

我正在使用 ILSpy 反编译 .Net 的程序集并查看代码。当我浏览 in 的代码时System.Windows.Vector.AngleBetween(Vector, Vector)WindowsBase.dll我偶然发现了一些奇怪的东西。

这是函数的完整代码:

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,这是一个常数。

这是Microsoft Docs关于 C# 中的常量的说法:

事实上,当编译器在 C# 源代码中遇到常量标识符时,它会将文字值直接替换为它生成的中间语言 (IL) 代码。

基于此,ILSpy 所做的似乎是不可能的。

注意:即使在设置中未选中“使用调试符号中的变量名,如果可用”和“显示调试符号中的信息,如果可用”选项,也会出现此行为。

4

2 回答 2

6

正如您在此ILSpy 问题和相应的拉取请求中所见,这是专门为众所周知的值实现(硬编码)的,例如Math.PI.

从 GitHub 问题:

我想通过以下方式计算 pi 系数 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-10T18:34:39.740 回答
0

LINQPad 中的快速测试显示生成的 IL 代码存在一些差异(从此处复制的 PI 常量值)。

资源:

void Main()
{
    double a = Math.PI;
    double b = 3.14159265358979;
}

伊利诺伊:

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 文档中的上述值似乎与.NET 参考源中的信息相矛盾(请参阅注释)。从源代码调整后,IL 是相同的。

资源:

void Main()
{
    var a = Math.PI;
    var b = 3.14159265358979323846;
}

伊利诺伊:

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   

顺便说一句,看起来有一个未解决的问题来解决文档/源代码不一致。

于 2019-04-10T18:27:10.787 回答