Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

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

.class
. Тем не менее, эта простая директива может быть декорирована многочисленными дополнительными атрибутами, уточняющими природу типа. В целях иллюстрации добавим в наше пространство имен открытый класс под названием
MyBaseClass
. Как и в С#, если базовый класс явно не указан, то тип автоматически становится производным от
System.Object
:

.namespace MyNamespace

{

// Предполагается базовый
класс System.Object.

.class public MyBaseClass {}

}

При построении типа, производного не от класса

System.Object
, применяется атрибут
extends
. Для ссылки на тип, определенный внутри той же самой сборки, язык CIL требует использования полностью заданного имени (однако если базовый тип находится внутри той же самой сборки, то префикс в виде дружественного имени сборки можно не указывать). Следовательно, демонстрируемая ниже попытка расширения
MyBaseClass
в результате дает ошибку на этапе компиляции:

// Этот код не скомпилируете»!

.namespace MyNamespace

{

.class public MyBaseClass {}

.class public MyDerivedClass

extends MyBaseClass {}

}

Чтобы корректно определить родительский класс для

MyDerivedClass
, потребуется указать полностью заданное имя
MyBaseClass
:

// Уже лучше!

.namespace MyNamespace

{

.class public MyBaseClass {}

.class public MyDerivedClass

extends MyNamespace.MyBaseClass {}

}

В дополнение к атрибутам

public
и
extends
определение класса CIL может иметь множество добавочных квалификаторов, которые управляют видимостью типа, компоновкой полей и т.д. В табл. 19.2 описаны избранные атрибуты, которые могут применяться в сочетании с директивой
.class
.

Определение и реализация интерфейсов в CIL

Несколько странно, но типы интерфейсов в CIL определяются с применением директивы

.class
. Тем не менее, когда директива
.class
декорирована атрибутом interface, тип трактуется как интерфейсный тип CTS. После определения интерфейс можно привязывать к типу класса или структуры с использованием атрибута
implements
:

.namespace MyNamespace

{

// Определение интерфейса.

.class public interface IMyInterface {}

// Простой базовый класс.

.class public MyBaseClass {}

// Теперь MyDerivedClass реализует IMylnterface

// и расширяет MyBaseClass.

.class public MyDerivedClass

extends MyNamespace.MyBaseClass

implements MyNamespace.IMyInterface {}

}

На

заметку!
Конструкция
extends
должна предшествовать конструкции
implements
. Кроме того, в конструкции
implements
может содержаться список интерфейсов с разделителями-запятыми

Вспомните из главы 8, что интерфейсы могут выступать в роли базовых для других типов интерфейсов, позволяя строить иерархии интерфейсов. Однако вопреки возможным ожиданиям применять атрибут

extends
для порождения интерфейса
А
от интерфейса
В
в CIL нельзя. Атрибут
extends
используется только для указания базового класса типа. Когда интерфейс необходимо расширить, снова будет применяться атрибут
implements
, например:

// Расширение интерфейсов в CIL.

.class public interface IMyInterface {}

.class public interface IMyOtherInterface

implements MyNamespace.IMyInterface {}

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

Директива

.class
может использоваться для определения любой структуры CTS, если тип расширяет
System.ValueType
. Кроме того, такая директива
.class
должна уточняться атрибутом
sealed
(учитывая, что структуры никогда не могут выступать в роли базовых для других типов значений). Если попытаться поступить иначе, тогда компилятор
ilasm.exe
выдаст сообщение об ошибке.

// Определение структуры всегда является запечатанным.

.class public sealed MyStruct

extends [System.Runtime]System.ValueType{}

Имейте в виду, что в CIL предусмотрен сокращенный синтаксис для определения типа структуры. В случае применения атрибута

value
новый тип автоматически становится производным от
[System.Runtime]System.ValueType
. Следовательно, тип
MyStruct
можно было бы определить и так:

// Сокращенный синтаксис объявления структуры.

.class public sealed value MyStruct{}

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

Перечисления .NET Core порождены от класса

System.Enum
, который является
System.ValueType
(и потому также должен быть запечатанным). Чтобы определить перечисление в CIL, необходимо просто расширить
[System.Runtime]System.Enum
:

// Перечисление.

.class public sealed MyEnum

extends [System.Runtime]System.Enum{}

Подобно структурам перечисления могут быть определены с помощью сокращенного синтаксиса, используя атрибут

enum
:

// Сокращенный синтаксис определения перечисления.

.class public sealed enum MyEnum{}

Вскоре вы увидите, как указывать пары "имя-значение" перечисления.

Поделиться с друзьями: