Чтение онлайн

ЖАНРЫ

ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание

Троелсен Эндрю

Шрифт:

// выполняемого файла.

.entrypoint

.maxstack.8

IL_0000: nop

IL_0001: ldstr "Hello CIL code!"

IL_0006: call void [mscorlib]System.Console::WriteLine(string)

IL_000b: nop

IL_000c: call string [mscorlib]System.Console::ReadLine

IL_0011: pop

IL_0012: ret

 }

 // Конструктор, заданный по умолчанию.

 .method public hidebysig specialname rtspecialname instance void .ctor cil managed {

.maxstack 8

IL_0000: ldarg.0

IL_0001: call instance void [mscorlib]System.Object::.ctor

IL_0006: ret

 }

}

Во-первых,

обратите внимание на то, что файл *.il начинается с объявления всех внешних компоновочных блоков, на которые ссылается данный компоновочный блок. Здесь вы видите только одну директиву .assembly extern для одного обязательно присутствующего mscorlib.dll. Если бы ваша библиотека классов использовала типы из других внешних компоновочных блоков, вы бы обнаружили дополнительные директивы .assembly extern.

Далее следует формальное определение вашего компоновочного блока HelloProgram.exe, для которого указана версия 0.0.0.0, назначаемая по умолчанию (если вы не укажете иное значение с помощью атрибута [AssemblyVersion]). После этого приводятся другие описания компоновочного блока, для которых используются другие директивы CIL (такие, как .module, .imagebase и т.д.).

После указания ссылок на внешние компоновочные блоки и определения текущего компоновочного блока идет определение типа Program. Обратите внимание на то, что директива.class имеет несколько атрибутов (многие из которых необязательны), – например, атрибут extends, задающий базовый класс типа.

.class private auto ansi beforefieldinit Program extends [mscorlib]System.Object {…}

Большой кусок программного кода CIL соответствует конструктору класса, заданному по умолчанию, и методу Main. Оба они определены (в частности) с помощью директивы .method. После определения этих членов с помощью подходящих директив и атрибутов они реализуются с помощью различных кодов операций.

Важно понять, что в CIL при взаимодействии с типами .NET (например, с System.Console) всегда необходимо использовать абсолютные имена типов. Более того, к абсолютному имени типа всегда должен добавляться (в квадратных скобках) префикс с понятным именем компоновочного блока, определяющего этот тип. Взгляните на CIL-реализацию Main.

.method private hidebysig static void Main(string[] args) cil managed {

 .entrypoint

 .maxstack 8

 IL_0000: nop

 IL_0001: ldstr "Hello CIL code!"

 IL_0006: call void [mscorlib]System.Console::WriteLine(string)

 IL_000b: nop

 IL_000c: call string [mscorlib]System.Console::ReadLine

 IL_0011: pop

 IL_0012: ret

}

Реализация конструктора, заданного по умолчанию, в терминах программного кода CIL включает еще одну относящуюся к загрузке инструкцию (ldarg.0). В данном случае значение загружается в стек не как пользовательская переменная, указанная нами, а как текущая объектная ссылка (подробности этого процесса будут описаны позже). Также обратите внимание на то, что конструктор, заданный по умолчанию, явно вызывает

конструктор базового класса.

.method public hidebysig specialname rtspecialname instance void .ctor cil managed {

 .maxstack 8

 IL_0000: ldarg.0

 IL_0001: call instance void [mscorlib]System.Object::.ctor

 IL_0006: ret

}

Роль меток в программном коде CIL

Вы. конечно, заметили, что в каждой строке программного кода реализации содержится префикс в форме лексемы IL_XXX: (например, IL_0000: IL_0001: и т.д.). Эти лексемы называются метками кода, и они могут иметь любой вид, какой вы только пожелаете (лишь бы они не дублировались в пределах одного и того же контекста). При записи содержимого компоновочного блока в файл с помощью ildasm.exe автоматически генерируются метки кода, имеющие вид IL_XXX:. Но вы можете изменить их с тем, чтобы они стали более информативными.

.method private hidebysig static void Main(string[] args) cil managed {

 .entrypoint

 .maxstack 8

 Nothing_1: nop

 Load_String: ldstr "Hello CIL code!"

 PrintToConsole: call void [mscorlib]System.Console::WriteLine(string)

 Nothing_2: nop

 WaitFor_KeyPress: call string [mscorlib] System.Console::ReadLine

 RemoveValueFromStack: pop

 Leave_Functlon: ret

}

Суть в том, что большинство меток кода совсем необязательно. Единственным случаем, когда метки кода оказываются по-настоящему полезными (и обязательными), является случай, когда в программном коде CIL используются ветвления или циклические конструкции. Например, в нашем случае вы можете исключить метки вообще.

.method private hidebysig static void Main(string[] args) cil managed {

 .entrypoint

 .maxstack 8

 nop

 ldstr "Hello CIL code!"

 call void [mscorlib]System.Console::WriteLine(string)

 nop

 call string [mscorlib]System.Console::ReadLine

 pop

 ret

}

Взаимодействие с CIL: модификация файла *.il

Теперь, когда вы понимаете, как компонуется базовый файл CIL, давайте завершим наш эксперимент с челночной технологией разработки программ. С помощью изменения CIL-кода в файле *.il мы должны выполнить следующее.

• Добавить ссылку на компоновочный блок System.Windows.Forms.dll.

• Загрузить локальную строку в Main.

• Вызвать метод System.Windows.Forms.MessageBox.Show, используя локальную строковую переменную в качестве его аргумента.

Первым шагом является добавление новой директивы.assembly (с атрибутом extern), которая укажет, что используется System.Windows.Forms.dll. Для этого просто добавьте в файл *.il следующую программную логику после ссылки на внешний компоновочный блок mscorlib.

Поделиться с друзьями: