Компилятор c# преобразует исходный код в промежуточный язык IL(Intermediate Language), из которого возможно преобразование в машинные команды доступные. Далее в игру вступает CLR(Common Language Runtime). CLR получает управляемые модули(обычно одна сборка хранит ровно один модуль(например, сборка ConsoleApp.dll, будет хранить только один модуль ConsoleApp, однако можно размещать несколько модулей в одной сборке, для этого нужно использовать префикс --addmodule, при запуске csc), при компиляции модуля вместе с IL кодом модуля, также генерируется метаданные, которые помогают работать IntelliSense и сборщику мусора отслеживать жизненный цикл объектов.При помощи метаданных сборщик мусора может определитьтип объектов и узнать как на них ссылкаются другие объекты.
После создания управляемых модулей компилятор объединяет их в единую сборку, также в сборку попадают файлы ресурсов(.txt,.html). У сборки есть манифест, который описывает файлы которые входят в сборку, экспортируемые типы, а также файлы ресурсов.
Для выполнение какого-либо метода нужно преобразовать IL код в машинные команды, этим занимается JIT (Just-In-Time) компилятор. Например, если в методе Main есть вызов Console.WriteLine(), то среда CLR выделяем внутреннюю структуру данный типа Console, в которой перечислены все методы, каждая запись метода содержит адрес по которой можно найти реализацию этого метода.При инициализации CLR заносит в каждую запись информации о методе вызов функции, Рихтер называет эту функцию JITCompiler. Когда программа первый раз обращается к методу WriteLine, происходит первый вызов функции JITCompiler. Эта функция преобразует IL code вызова этого метода в машинные команды и передает управление этим машинным командам.Также JITCompiler заменяет адрес этого метода адресом динамически сгенерированных машинных команд, чтобы при повторном вызове функции они сразу выполнялись. Неуправляемый код генерируется сразу в машинные команды. JIT компилятор хранит машинные команды в динамической памяти, поэтому при повторной компиляции IL код также будет преобразовываться в машинные команды, т.е JIT компилятор будет снова делать то же самое. В этом управляемый код проигрывает неуправляемому, приходится каждый раз по новой выполнять процесс JIT компиляции. Существует несколько различных параметров определющих насколько код будет оптимизирован при компиляции в IL и JIT компиляции, поэтому когда программа запускается без отладки, компиляция проходит быстрее. Все дело в том, что при компиляции с флагом /optimize-/debug+ генерируется неоптимальный IL код, который поддерживает отладку, также они позволяет ставить точки останова на управляющих командах, типо for,while или в блоках try/catch/finally. Если JIT Compiler не обеспечивает приложению должный уровень производительности, то можно воспользоваться утилитой NGen.exe. Она сразу компилирует IL код в машинный и clr смотрит, cуществует ли уже скомпилированная версия сборки, если да, то использует ее. Также существует класс System.Runtime.ProfileOptimizator, который при компиляции запоминает, какие методы JIT компилятору пришлось компилировать, и при следующей компиляции, компилирует их параллельно в других программных потоках(если машина оснащена несколькими процессорами) при инициализации приложения.
Основное преимущество использование предварительной компиляции это верификация кода, CLR сам может проанализировать некоторые конструкции, например что невозможно привести один тип к другому, либо, что невозможно вызвать метод с недостаточным количеством параметров, таким образом код генерируемый CLR является безопасным. Что позволяет запускать несколько приложений в одном адресном пространстве не боясь, что они могут повредить чужие области в памяти. Каждое управляемое приложение выполняется в своем домене приложений(AppDomain)
Код,неуправляемый CLR, очень опасен, поскольку позволяет обращаться к участкам памяти других программ, и может испортить работу программы
Посколько IL высокоуровневый язык, некоторые люди опасаются, что его можно декомпилировать обратно в код, да, это так, если существуют такие опасение можно зашифровать названия методов или публиковать его как скомпилированные машинные команды используя NGen.exe
Компилирует весь код в машинные команды, чтобы при выполнении проекта запускались они, а не IL код с JIT компилятором
Базовая библиотека .net framework
Общая система типов CLR В соответсвии с CTS тип может содеражть 0 или более членов, таких как: 1)Свойство 2)Поле 3)Метод 4)Событие
CTS также управляем видимостью типов, например 1)Публичный 2)Приватный 3)Защищенный(для наследников) 4)Доступ только в сборке(internal) 5)Доступ для наследников во всех сборках и всех типов в этой сборке(в C# нет) 6)Доступ для всех в этой сборке и наследников в других сборках (protected internal)
Также у CLR есть определенные правила взаимодействия классов, например запрещено множественное наследование, и все типы должны быть производными от типа Object, в котором определены методы:
- ToString()
- Clone()
- GetHashCode()
- Equals(T value)
- GetType()
???Неуправляемый код компилируется сразу в машинные команды??