Как декомпилятор может распознать скомпилированную константу? - PullRequest
3 голосов
/ 10 апреля 2019

Я использую ILSpy для декомпиляции сборок .Net и просмотра кода. Просматривая код 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 говорит о константах в C #:

Фактически, когда компилятор встречает постоянный идентификатор в исходном коде C #, он подставляет буквенное значение непосредственно в код промежуточного языка (IL), который он создает.

Исходя из этого, то, что сделал ILSpy, кажется невозможным.

Примечание: это поведение присутствует, даже если «Использовать имена переменных из символов отладки, если они доступны» и «Показать информацию из символов отладки, если они доступны» опции не отмечены в настройках.

Ответы [ 2 ]

6 голосов
/ 10 апреля 2019

Как вы можете видеть в этой проблеме ILSpy и соответствующем запросе на получение , это было специально реализовано (жестко задано) для известных значений, таких как 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 и т. Д.).

0 голосов
/ 10 апреля 2019

Быстрый тест в LINQPad показывает некоторые различия в сгенерированном коде IL (значение константы 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 противоречат информации из .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   

Кроме того, похоже, что существует открытый выпуск для устранения несоответствия документации / исходного кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...