Литмир - Электронная Библиотека
A
A

   IL_0011:  ret

 } // end of method '<Program>$'::'<Main>$'

Роль меток в коде CIL

Вы определенно заметили, что каждая строка в коде реализации предваряется лексемой в форме

IL_X
XX: (например,
IL_0000:
,
IL_0001:
и т.д.). Такие лексемы называются метками кода и могут именоваться в любой выбранной вами манере (при условии, что они не дублируются внутри области действия члена). При сбросе содержимого сборки в файл утилита
ildasm.exe
автоматически генерирует метки кода, которые следуют соглашению об именовании вида
IL_XXXX:
. Однако их можно заменить более описательными маркерами, например:

.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 [System.Console]System.Console::WriteLine(string)

  Nothing_2: nop

  WaitFor_KeyPress: call string [System.Console]System.Console::ReadLine()

  RemoveValueFromStack: pop

  Leave_Function: ret

}

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

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

{

  .entrypoint

  .maxstack 8

  nop

  ldstr "Hello CIL code!"

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

  nop

  call string [System.Console]System.Console::ReadLine()

  pop

  ret

}

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

Теперь, когда вы имеете представление о том, из чего состоит базовый файл CIL, давайте завершим эксперимент с возвратным проектированием. Цель здесь довольно проста: изменить сообщение, которое выводится в окно консоли. Вы можете делать что-то большее, скажем, добавлять ссылки на сборки или создавать новые классы и методы, но мы ограничимся простым примером.

Чтобы внести изменение, вам понадобится модифицировать текущую реализацию операторов верхнего уровня, созданную в виде метода

<Main>$()
. Отыщите этот метод в файле
*.il
и измените сообщение на
"Hello from altered CIL code!"
.

Фактически код CIL был модифицирован для соответствия следующему определению на языке С#:

static void Main(string[] args)

{

  Console.WriteLine("Hello from altered CIL code!");

  Console.ReadLine();

}

Компиляция кода CIL

Предшествующие версии .NET позволяли компилировать файлы

*.il
с применением утилиты ilasm.exe. В .NET Core положение дел изменилось. Для компиляции файлов
*.il
вы должны использовать тип проекта
Microsoft.NET.Sdk.IL
. На момент написания главы он все еще не был частью стандартного комплекта SDK.

Начните с создания нового каталога на своей машине. Создайте в этом каталоге файл

global.json
, который применяется к текущему каталогу и всем его подкаталогам. Он используется для определения версии комплекта SDK, которая будет задействована при запуске команд .NET Core CLI. Модифицируйте содержимое файла, как показано ниже:

{

  "msbuild-sdks": {

    "Microsoft.NET.Sdk.IL": "5.0.0-preview.1.20120.5"

  }

}

На следующем шаге создается файл проекта. Создайте файл по имени

RoundTrip.ilproj
и приведите его содержимое к следующему виду:

<Project Sdk="Microsoft.NET.Sdk.IL">

  <PropertyGroup>

    <OutputType>Exe</OutputType>

    <TargetFramework>net5.0</TargetFramework>

     <MicrosoftNetCoreIlasmPackageVersion>

        5.0.0-preview.1.20120.5

     </
MicrosoftNetCoreIlasmPackageVersion>

    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>

  </PropertyGroup>

</Project>

Наконец, скопируйте созданный файл

RoundTrip.il
в каталог проекта. Скомпилируйте сборку с применением .NET Core CLI:

dotnet build

Результирующие файлы будут находиться, как обычно, в подкаталоге

bin\debug\net5.0
. На этом этапе новое приложение можно запустить. Разумеется, в окне консоли отобразится обновленное сообщение. Хотя приведенный простой пример не является особенно впечатляющим, он иллюстрирует один из сценариев применения возвратного проектирования на CIL.

Директивы и атрибуты CIL

Теперь, когда вы знаете, как преобразовывать сборки .NET Core в файлы

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

349
{"b":"847442","o":1}