Например, если ваше .NET-приложение предназначено для выполнения на "компактном" устройстве (таком, как, например, КПК), то соответствующий JIT-компилятор будет иметь специальные средства для учета условий ограниченности памяти. Если это компоновочный блок для серверной системы (где объем памяти редко оказывается проблемой), то соответствующий JIT-компилятор будет оптимизирован для работы в условиях достаточного объема памяти. Таким образом разработчики получают возможность создавать только один блок программного кода, который с помощью JIT-компиляции можно выполнять на машинах с разной архитектурой.
К тому же, при компиляции CIL-инструкций в соответствующий машинный код JIT-компилятор поместит результаты компиляции в кэш в соответствии с тем, как этого требует соответствующая операционная система. Так, при первом вызове метода с именем PrintDocument() соответствующие CIL-инструкции компилируются в конкретные инструкции платформы и сохраняются в памяти для использования в дальнейшем. Поэтому при следующих вызовах PrintDocument () необходимости в повторной компиляции CIL не возникает.
Роль метаданных типов .NET
Кроме CIL-инструкций, компоновочный блок .NET содержит исчерпывающие и точные метаданные, описывающие все его типы (классы, структуры, перечни и т.д.), определенные в бинарном объекте, и все члены каждого типа (свойства, методы, события и т.д.). К счастью, задача создания метаданных всегда возлагается на компилятор (а не на программиста). По причине того, что метаданные .NET так подробны и точны, компоновочные блоки оказываются единицами, способными себя полностью описать, – настолько полно, что для бинарных .NET-объектов не возникает необходимости регистрироваться в реестре системы.
Для иллюстрации формата метаданных типов .NET давайте рассмотрим метаданные, сгенерированные для метода Add() C#-класса Calc, представленного выше (метаданные, генерируемые для VB .NET-версии метода Add(), оказываются аналогичными).
TypeDef #2 (02000003)
-----------------------------------------------------------
TypDefName: CalculatorExample.Calc (02000003)
Flags: [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldlnit] (00100001)
Extends: 01000001 [TypeRef] System.Object
Method #1 (06000003)
-----------------------------------------------------------
MethodName: Add (06000003)
Flags: [Public] [HideBySig] [ReuseSlot] (00000086)
RVA: 0x00002090
ImplFlags: [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: I4
2 Arguments
Argument #1: I4
Argument #2: I4
2 Parameters
(1) ParamToken: (08000001) Name: x flags: [none] (00000000)
(2) ParamToken: (08000002) Name: у flags: [none] (00000000)
Метаданные используются средой выполнения .NET, а также различными средствами разработки. Например, возможность IntelliSense, предлагаемая в Visual Studio 2005 в режиме проектирования, основана на чтении метаданных компоновочного блока. Метаданные используются различными утилитами просмотра объектов, инструментами отладки и самим компилятором C#. Для полноты картины заметим также, что использование метаданных лежит в основе множества .NET-технологий, включая удаленный доступ, отображение типов, динамическое связывание, Web-сервисы XML и сериализацию объектов.
Роль манифеста компоновочного блока
Наконец вспомним, что компоновочный блок .NET содержит также метаданные, описывающие сам компоновочный блок (эти метаданные называются манифест). Среди всего прочего, в манифесте документируются все внешние компоновочные блоки, которые требуются текущему компоновочному блоку для корректного функционирования, указан номер версии компоновочного блока, информация об авторских правах и т.д. Подобно метаданным типов, генерирование манифеста компоновочного блока тоже является задачей компилятора. Вот некоторые подходящие для иллюстрации элементы манифеста CSharpCalculator.exe.
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89)
.ver 2:0:0:0
}
.assembly CSharpCalculator
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module CSharpCalculator.exe
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
По сути, этот манифест содержит указания на внешние компоновочные блоки, необходимые для CSharpCalculator.exe (для этого используется директива.assembly extern), а также различные характеристики самого компоновочного блока (номер версии, имя модуля и т.д.).