Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 229 230 231 232 233 234 235 236 237 ... 407
члены отображаются на примитивы CIL.

Определение полей данных в CIL

Перечисления, структуры и классы могут поддерживать поля данных. Во всех случаях для их определения будет использоваться директива .field. Например, добавьте к перечислению MyEnum следующие три пары "имя-значение" (обратите внимание, что значения указаны в круглых скобках):

.class public sealed enum MyEnum

{

  .field public static literal valuetype

   MyNamespace.MyEnum A = int32(0)

  .field public static literal valuetype

   MyNamespace.MyEnum B = int32(1)

   .field public static literal valuetype

   MyNamespace.MyEnum C = int32(2)

}

Поля, находящиеся внутри области действия производного от System.Enum типа .NET Core, уточняются с применением атрибутов static и literal. Как не трудно догадаться, эти атрибуты указывают, что данные полей должны быть фиксированными значениями, доступными только из самого типа (например, MyEnum.А).

На заметку! Значения, присваиваемые полям в перечислении, также могут быть представлены в шестнадцатеричном формате с префиксом 0х.

Конечно, когда нужно определить элемент поля данных внутри класса или структуры, вы не ограничены только открытыми статическими литеральными данными. Например, класс MyBaseClass можно было бы модифицировать для поддержки двух закрытых полей данных уровня экземпляра со стандартными значениями:

.class public MyBaseClass

{

  .field private string stringField = "hello!"

  .field private int32 intField = int32(42)

}

Как и в С#, поля данных класса будут автоматически инициализироваться подходящими стандартными значениями. Чтобы предоставить пользователю объекта возможность указывать собственные значения во время создания закрытых полей данных, потребуется создать специальные конструкторы.

Определение конструкторов типа в CIL

Спецификация CTS поддерживает создание конструкторов как уровня экземпляра, так и уровня класса (статических). В CIL конструкторы уровня экземпляра представляются с использованием лексемы .ctor, тогда как конструкторы уровня класса — посредством лексемы .cctor (class constructor — конструктор класса). Обе лексемы CIL должны сопровождаться атрибутами rtspecialname (return type special name — специальное имя возвращаемого типа) и specialname. Упомянутые атрибуты применяются для обозначения специфической лексемы CIL, которая может трактоваться уникальным образом в любом отдельно взятом языке .NET Core. Например, в языке C# конструкторы не определяют возвращаемый тип, но в CIL возвращаемым значением конструктора на самом деле является void:

.class public MyBaseClass

{

  .field private string stringField

  .field private int32 intField

  .method public hidebysig specialname rtspecialname

    instance void .ctor(string s, int32 i) cil managed

  {

    // Добавить код реализации...

  }

}

Обратите внимание, что директива .ctor снабжена атрибутом instance (поскольку конструктор не статический). Атрибуты cil managed указывают на то, что внутри данного метода содержится код CIL, а не неуправляемый код, который может использоваться при выполнении запросов Р/Invoke.

Определение свойств в CIL

Свойства и методы также имеют специфические представления в CIL. В качестве примера модифицируйте класс MyBaseClass с целью поддержки открытого свойства по имени TheString, написав следующий код CIL (обратите внимание на применение атрибута specialname):

.class public MyBaseClass

{

  ...

  .method public hidebysig specialname

    instance string get_TheString() cil managed

  {

    // Добавить код реализации...

  }

  .method public hidebysig specialname

    instance void set_TheString(string 'value') cil managed

  {

    // Добавить код реализации...

  }

  .property instance string TheString()

  {

    .get instance string

      MyNamespace.MyBaseClass::get_TheString()

    .set instance void

      MyNamespace.MyBaseClass::set_TheString(string)

  }

}

В терминах CIL свойство отображается на пару методов, имеющих префиксы get_ и set_. В директиве .property используются связанные директивы .get и .set для отображения синтаксиса свойств на подходящие "специально именованные" методы.

На заметку! Обратите внимание, что входной параметр метода set в свойстве помещен в одинарные кавычки и представляет имя лексемы, которая должна применяться в правой части операции присваивания внутри области определения метода.

Определение параметров членов

Коротко говоря, параметры в CIL указываются (более или менее) идентично тому, как это делается в С#. Например, каждый параметр определяется путем указания его типа данных, за которым следует имя параметра. Более того, подобно C# язык CIL позволяет определять входные, выходные и передаваемые по ссылке параметры. Вдобавок в CIL допускается определять массив параметров (соответствует ключевому слову params в С#), а также необязательные параметры.

Чтобы проиллюстрировать процесс определения параметров в низкоуровневом коде CIL, предположим, что необходимо построить метод, который принимает параметр int32 (по значению), параметр int32 (по ссылке), параметр [System.Runtime.Extensions]System.Collection.ArrayList и один выходной параметр (типа int32). В C# метод выглядел бы примерно так:

public static void MyMethod(int inputInt,

  ref int refInt, ArrayList ar, out int outputInt)

{

  outputInt = 0; // Просто чтобы удовлетворить компилятор C#...

}

После отображения метода MyMethod() на код CIL вы обнаружите, что ссылочные параметры C# помечаются символом амперсанда (&), который дополняет лежащий в основе тип данных (int32 &).

Выходные параметры также снабжаются суффиксом &, но дополнительно уточняются лексемой [out] языка CIL. Вдобавок если параметр относится к ссылочному типу ([System.RuntimeExtensions]System.Collections.ArrayList), то перед типом данных указывается лексема class (не путайте ее с директивой .class):

.method public hidebysig static void MyMethod(int32 inputInt,

  int32& refInt,

  class [System.Runtime.Extensions]System.Collections.ArrayList ar,

  [out] int32& outputInt) cil managed

{

  ...

}

Исследование кодов операций CIL

Последний аспект кода CIL, который будет здесь рассматриваться, связан с ролью разнообразных кодов операций. Вспомните, что код операции — это просто лексема CIL, используемая при построении логики реализации для заданного члена.

Все коды операций CIL (которых довольно много) могут быть разделены на три обширные категории:

• коды операций, которые управляют потоком выполнения программы ;

• коды операций, которые вычисляют выражения;

• коды операций, которые получают доступ к значениям в памяти (через параметры, локальные переменные

1 ... 229 230 231 232 233 234 235 236 237 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий