Заметьте, однако, что для создания CILCar используется код операции.newobj. В связи с этим напомним, что при вызове члена типа непосредственно в CIL вы должны применить синтаксис с использованием двойного двоеточия и, как всегда, указать абсолютное имя типа. Восприняв сказанное, вы можете скомпилировать свой новый файл с помощью ilasm.exe, проверить полученный компоновочный блок с помощью peverifу.exe, а затем выполнить программу.
ilasm CilCarClient.il
peverify CilCarClient.exe
CILCarClient.exe
На рис. 15.5 показан конечный результат.
Рис. 15.5. Ваш CILCar в действии
На этом, выполнив первую задачу этой главы, мы закончим освоение азбуки CIL. К этому моменту, я надеюсь, вы уверенно сможете открыть любой компоновочный блок .NET с помощью ildasm.exe и лучше понимаете, что происходит внутри него.
Динамические компоновочные блоки
Как видите, процесс создания сложного приложения .NET непосредственно в CIL оказывается довольно трудоемким. С одной стороны, CIL является чрезвычайно выразительным языком программирования, позволяющим взаимодействовать со всеми программными конструкциями, допустимыми в CTS. С другой стороны, создание CIL-кода является делом скучным, утомительным и сопряженным с множеством ошибок. Хотя верно и то, что знание – это сила, вы можете поинтересоваться, действительно ли это так важно, чтобы "загромождать" законами синтаксиса CIL свою память. Я отвечу так: это зависит от многого. Конечно, для большинства ваших .NET-проектов рассматривать, редактировать или непосредственно создавать программный код CIL не потребуется. Но, освоив азбуку CIL, вы теперь готовы к обсуждению динамических компоновочных блоков (которые называются так в противоположность статическим компоновочным блокам) и роли пространства имен System.Reflection.Emit.
Здесь сразу же может возникнуть вопрос: "В чем разница между статическими и динамическими компоновочными блоками?" По определению,
Конечно, создание динамических компоновочных блоков является довольно сложным (и не слишком часто применяемым) приемом программирования, но этот подход может оказаться полезным в следующих обстоятельствах,
• При создании инструментов программирования .NET. позволяющих по требованию динамически генерировать компоновочные блоки в зависимости от пользовательского ввода.
• При создании программ, способных динамически генерировать агенты доступа к удаленным типам на основе получаемых метаданных.
• При загрузке статических компоновочных блоков с динамическим добавлением новых типов в двоичный образ.
Учитывая сказанное, давайте рассмотрим типы, предлагаемые в System.Reflection.Emit.
Исследование пространства имен System.Reflection.Emit
Для создания динамического компоновочного блока требуется в определенной мере понимать коды операций CIL, но типы пространства имен System.Reflection. Emit в максимальной мере "пытаются" скрыть сложность CIL. Например, вместо прямого указания необходимых директив и атрибутов CIL при определении типа класса вы можете просто использовать класс TypeBuilder. Точно так же, чтобы определить новый конструктор уровня экземпляра, нет никакой необходимости использовать specialname, rtspecialname и лексемы .ctor – вместо этого можно просто использовать ConstructorBuilder. Описания ключевых членов пространства имен System.Reflection.Emit приводятся в табл. 15.8.
Таблица 15.8. Избранные члены пространства имен System.Reflection.Emit