Синтаксис языка CIL
36C# --- Сборки .NET --- Синтаксис языка CIL
Язык CIL является самым настоящим "родным" языком для платформы .NET. При создании .NET-сборки с помощью того или иного языка (C#, VB, COBOL.NET и т.д.) соответствующий компилятор всегда преобразует исходный код на этом языке в код на CIL. Как и в любом другом языке программирования, в CIL поддерживается множество связанных со структурированием и реализацией лексем. Поскольку CIL представляет собой просто еще один язык программирования .NET, не должен удивлять тот факт, что сборки .NET можно создавать непосредственно на CIL и компилировать их с помощью компилятора ilasm.exe, который входит в состав .NET Framework 4.0 SDK.
Хотя желание построить все приложение .NET непосредственно на CIL действительно будет возникать у очень немногих, все равно этот язык является чрезвычайно интересным объектом для изучения. Хорошие знания грамматики языка CIL позволяют совершенствовать приемы разработки .NET-приложений. Разработчики, разбирающиеся в CIL, способны делать следующее:
Точно знать, на какие лексемы в CIL отображаются ключевые слова из различных языков программирования .NET.
Дизассемблировать существующие .NET-сборки, редактировать лежащий в их основе CIL-код и заново компилировать обновленную кодовую базу в новый двоичный файл .NET. Например, некоторые сценарии могут требовать внесения изменений в CIL-код для взаимодействия с расширенными средствами СОМ.
Строить динамические сборки с использованием пространства имен System.Reflection.Emit. Этот API-интерфейс позволяет генерировать сборку .NET в памяти, которая впоследствии может быть сохранена на диске.
Использовать такие возможности CTS (Common Type System — общая система типов), которые в управляемых языках более высокого уровня не поддерживаются, а на уровне CIL действительно доступны. На самом деле CIL является единственным языком .NET, который позволяет получать доступ ко всем возможностям CTS. Например, используя чистый код CIL, можно создавать определения глобальных членов и полей (чего в C# делать не разрешено).
Следует еще раз подчеркнуть, что овладеть навыками работы с C# и библиотеками базовых классов .NET можно и без изучения деталей CIL-кода. Во многих отношениях знание языка CIL для программиста, работающего с .NET, аналогично знанию языка ассемблера для программиста, работающего на С (С++). Те, кто разбирается в низкоуровневых деталях, способны создавать более совершенные решения для существующих задач и лучше понимают, как работает базовая среда программирования (и выполнения). Поэтому всем, кому интересно, предлагаем приступить к изучению основных аспектов CIL.
Важно отметить, что всестороннее и исчерпывающее описание синтаксиса и семантики CIL приведенo в официальной спецификации ЕСМА (ecma-335.pdf), доступной на веб-сайте ЕСМА International по адресу http://www.ecma-international.org.
В отличие от такого высокоуровневого языка, как C#, в CIL не поставляется простой общий набор ключевых слов. Вместо этого набор лексем, распознаваемых компилятором CIL, семантически разделен на три следующих основных категории: директивы CIL, атрибуты CIL и коды операций CIL.
Директивы CIL
Прежде всего, в CIL имеется ряд хорошо известных лексем, которые применяются для описания общей структуры .NET-сборки. Эти лексемы называются директивами. Директивы CIL позволяют информировать компилятор CIL о том, каким образом должны определяться пространства имен, типы и члены, входящие в состав сборки.
Синтаксически директивы представляются с использованием префикса в виде точки (.), например, .namespace, .class, .publickeytoken, .override, .method, .assembly и т.д. Следовательно, если в файле с расширением *.il (принятое по соглашению расширение для файлов CIL-кода) есть одна директива .namespace и три директивы .class, компилятор CIL будет генерировать сборку, в которой определено единственное пространство имен, содержащее три типа классов .NET
Атрибуты CIL
Во многих случаях сами по себе директивы CIL оказываются недостаточно описательными для того, чтобы полностью отражать определение того или иного типа или члена типа .NET. В таких случаях они могут сопровождаться различными атрибутами CIL, которые уточняют то, каким образом они должны обрабатываться. Например, директива .class может сопровождаться атрибутами public (уточняющим видимость типа), extends (явно указывающим базовый класс типа) и implements (позволяющим перечислить интерфейсы, поддерживаемые данным типом).
Коды операций CIL
После определения сборки, пространства имен и набора типов на CIL с помощью различных директив и соответствующих атрибутов, последнее, что останется сделать — это предоставить для каждого из типов логику реализации. Для решения этой задачи в CIL поддерживаются так называемые коды операций (operation codes — opcodes). Как и в других низкоуровневых языках программирования, коды операций в CIL обычно имеют непонятный и нечитабельный вид. Например, для загрузки в память переменной string в CIL должен применяться код операции не с удобным для восприятия именем вроде LoadString, а со сложным для произношения именем ldstr.
Некоторые коды операций в CIL отображаются вполне естественным образом на соответствующие аналоги в C# (например, box, unbox, throw и sizeof). Коды операций в CIL всегда применяются только в рамках реализации членов и, в отличие от директив, никогда не сопровождаются префиксом в виде точки.