Search code examples
c#decompilingcompile-time-constantilspy

How is a decompiler able to recognize a compiled constant?


I am using ILSpy to decompile the assemblies of .Net and look into the code. As I was browsing the code of System.Windows.Vector.AngleBetween(Vector, Vector) in WindowsBase.dll, I stumbled across something bizarre.

This is the full code of the function:

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);
}

Apparently ILSpy could recognize Math.PI, which is a constant.

This is what Microsoft Docs says about constants in C#:

In fact, when the compiler encounters a constant identifier in C# source code, it substitutes the literal value directly into the intermediate language (IL) code that it produces.

Based on this, what ILSpy did seems impossible.

Note: this behavior is present even if the "Use variable names from debug symbols, if available" and "Show info from debug symbols, if available" options are unchecked in the settings.


Solution

  • As you can see in this ILSpy issue and the corresponding pull request, this was specifically implemented (hardcoded) for well-known values such as Math.PI.

    From the GitHub issue:

    I suppose to calculate pi coefficient by following way: c = Math.PI / constant. If we getting "good" value (equal exactly to 1.0, 2.0, 0.5, 1/180 and so on), we simply replacing it with symbolic expression (Math.PI, Math.PI * 2, Math.PI / 2, Math.PI / 180 and so on).