Как и когда .NET фактически компилирует код? - PullRequest
7 голосов
/ 06 августа 2009

Допустим, вы пишете приложение на C #, VB, что угодно с .NET Когда вы нажимаете «build», действительно ли он компилирует ваш код? Я так думал, пока не начал использовать отражатель redgates на некоторых моих сборках и дословно увидел свой код. Я ожидал, что циклы будут развернуты и еще одно множество оптимизаций, а не ничего.

Так когда же на самом деле происходит компиляция? Я думаю, что когда он построен, код становится IL (промежуточный язык), а когда выполнение происходит, он загружается в CLR? Оптимизирован ли он только во время CLR, а не во время сборки?

Ответы [ 2 ]

22 голосов
/ 06 августа 2009

Когда вы компилируете в VS

  1. Ваш исходный код скомпилирован в байт-код, известный как общий промежуточный язык (CIL) или MSIL (Microsoft Intermediate Language).
  2. Метаданные из каждого класса и всех методов (и любой другой вещи: O) включены в PE-заголовок результирующего исполняемого файла (будь то dll или exe).
  3. Если вы создаете исполняемый файл, в PE Header также входит обычный загрузчик, который отвечает за загрузку CLR (общеязыковой среды выполнения) при выполнении исполняемого файла.

При выполнении:

  1. Загрузчик инициализирует CLR (в основном, загружая сборку mscorlib) и инструктирует его выполнить вашу сборку.
  2. CLR выполняет вашу основную запись.
  3. Теперь у классов есть векторная таблица, в которой хранятся адреса функций метода, поэтому при вызове MyMethod эта таблица ищется, а затем делается соответствующий вызов этого адреса. После запуска ВСЕ записи для всех таблиц имеют адрес JIT-компилятора.
  4. Когда выполняется вызов одного из таких методов, JIT вызывается вместо фактического метода и получает управление. Затем JIT компилирует код CIL в реальный код сборки для соответствующей архитектуры.
  5. Как только код скомпилирован, JIT переходит в таблицу векторов методов и заменяет адрес на адрес скомпилированного кода, чтобы каждый последующий вызов больше не вызывал JIT.
  6. Наконец, JIT обрабатывает выполнение скомпилированного кода.
  7. Если вы вызываете другой метод, который еще не был скомпилирован, вернитесь к 4 ... и так далее ...

Я также публикую ответ здесь, так как другой вопрос был не совсем об этом ...

4 голосов
/ 06 августа 2009

Он компилируется до IL во время компиляции. Волшебство Reflector заключается в том, что он «понимает» IL и преобразует его обратно в c # (или VB.NET или что-то еще. Посмотрите в меню «Параметры» в Reflector, и вы можете просмотреть сборку в любом формате, включая IL).

В Reflector вы фактически не видите свой оригинальный код. Вы видите перевод IL на c #. В большинстве случаев это будет очень похоже на то, что вы написали, но есть некоторые явные признаки - например, найдите место, где вы реализовали авто-свойство :

string MyProperty {get;set;}

И вы увидите, к чему это на самом деле компилируется, что-то вроде этого:

public string MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}
...