Указание ссылок на внешние сборки в CIL
Скопируйте файлы
global.json
и
NuGet.config
из предыдущего примера в новый каталог проекта. Создайте новый файл проекта по имени
CILTypes.ilproj
, содержимое которого показано ниже:
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<MicrosoftNetCoreIlasmPackageVersion>
5.0.0-preview.1.20120.5
</MicrosoftNetCoreIlasmPackageVersion>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
</PropertyGroup>
</Project>
Затем создайте в текстовом редакторе новый файл по имени
CILTypes.il
. Первой задачей в проекте CIL является перечисление внешних сборок, которые будут задействованы текущей сборкой. В рассматриваемом примере применяются только типы, находящиеся внутри сборки
System.Runtime.dll
. В новом файле понадобится указать директиву
.assembly
с уточняющим атрибутом
external
. При добавлении ссылки на сборку со строгим именем, подобную
System.Runtime.dll
, также должны быть указаны директивы
.publickeytoken
и
.ver
:
.assembly extern System.Runtime
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
.ver 5:0:0:0
}
Определение текущей сборки в CIL
Следующее действие заключается в определении создаваемой сборки с использованием директивы
.assembly
. В простейшем случае сборка может быть определена за счет указания дружественного имени двоичного файла:
<b>// Наша сборка.</b>
.assembly CILTypes{}
Хотя такой код действительно определяет новую сборку .NET Core, обычно внутрь объявления будут помещаться дополнительные директивы. В рассматриваемом примере определение сборки необходимо снабдить номером версии 1.0.0.0 посредством директивы
.ver
(обратите внимание, что числа в номере версии отделяются друг от друга
двоеточиями, а не точками, как принято в С#):
<b>// Наша сборка.</b>
.assembly CILTypes
{
<b> .ver 1:0:0:0</b>
}
Из-за того, что сборка
CILTypes
является однофайловой, ее определение завершается с применением следующей директивы
.module
, которая обозначает официальное имя двоичного файла .NET Core, т.е.
CILTypes.dll
:
// Наша сборка
.assembly CILTypes
{
.ver 1:0:0:0
}
// Модуль нашей однофайловой сборки.
.module CILTypes.dll
Кроме
.assembly
и
.module
существуют директивы CIL, которые позволяют дополнительно уточнять общую структуру создаваемого двоичного файла .NET Core. В табл. 19.1 перечислены некоторые наиболее распространенные директивы уровня сборки.
Определение пространств имен в CIL
Определив внешний вид и поведение сборки (а также обязательные внешние ссылки), вы можете создать пространство имен .NET Core (
MyNamespace
), используя директиву
.namespace
:
<b>// Наша сборка имеет единственное пространство имен.</b>
.namespace MyNamespace {}
Подобно C# определения пространств имен CIL могут быть вложены в другие пространства имен. Хотя здесь нет нужды определять корневое пространство имен, ради интереса посмотрим, как создать корневое пространство имен
MyCompany
:
.namespace MyCompany
{
.namespace MyNamespace {}
}
Как и С#, язык CIL позволяет определить вложенное пространство имен следующим образом:
<b>// Определение вложенного пространства имен.</b>
.namespace MyCompany.MyNamespace {}
Определение типов классов в CIL
Пустые пространства имен не особо интересны, поэтому давайте рассмотрим процесс определения типов классов в CIL. Для определения нового типа класса предназначена директива
.class
. Тем не менее, эта простая директива может быть декорирована многочисленными дополнительными атрибутами, уточняющими природу типа. В целях иллюстрации добавим в наше пространство имен открытый класс под названием
MyBaseClass
. Как и в С#, если базовый класс явно не указан, то тип автоматически становится производным от
System.Object
:
.namespace MyNamespace
{
<b> // Предполагается базовый класс System.Object.</b>
.class public MyBaseClass {}
}
При построении типа, производного не от класса
System.Object
, применяется атрибут
extends
. Для ссылки на тип, определенный внутри той же самой сборки, язык CIL требует использования полностью заданного имени (однако если базовый тип находится внутри той же самой сборки, то префикс в виде дружественного имени сборки можно не указывать). Следовательно, демонстрируемая ниже попытка расширения
MyBaseClass
в результате дает ошибку на этапе компиляции: