Я использую 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
, что является константой.
Вот что Документы Майкрософт говорит о константах в 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.
Исходя из этого, то, что сделал ILSpy, кажется невозможным.
Примечание. Это поведение присутствует, даже если «Использовать имена переменных из символов отладки, если они доступны» и «Показывать информацию из символов отладки, если они доступны». параметры не отмечены в настройках.
Быстрый тест в 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
Кроме того, похоже, что существует открытый вопрос для устранения несоответствия документации/исходного кода.
Math.PI
определенно является константой, это объявление: public const double PI = 3.1415926535897931;
Я просто обращался к документации MSDN из docs.microsoft.com/en-us/dotnet/api/…, в которой это указано как поле.
Значение, которое вы даете, также отличается от значения в связанной документации.
Согласно Справочный источник C#, вы правы. он объявлен как константа. Я скорректирую свой ответ.
Как вы можете видеть в этом ILSpy проблема и соответствующем пул реквест, это было специально реализовано (жестко закодировано) для известных значений, таких как Math.PI
.
Из проблемы GitHub:
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).
Как тогда ILSpy может распознавать малоизвестные константы?
У вас есть пример неизвестной константы, которую он распознает?
@DmytroMukalov Вероятно, он может распознавать малоизвестные константы из символов отладки (файлы PDB), но я не проверял это.
@DmytroMukalov Я только что проверил, и он не распознал Math.PI * 254.543
, даже с включенным «использовать символы отладки»
Возможно, ILSpy просто знает значение общих констант, таких как
Math.PI
, когда видит их.