Введение в MSIL - Часть 3: Определение типов — Архив WASM.RU

Все статьи

Введение в MSIL - Часть 3: Определение типов — Архив WASM.RU

В этой части я объясню, как задаются типы.

Вот минимальный ссылочный тип под названием House ("дом", - прим. пер.).

.class Kerr.RealEstate.House
{
    .method public void .ctor()
    {
        .maxstack 1
        
        ldarg.0 // push "this" instance onto the stack
        call instance void [mscorlib]System.Object::.ctor()
        
        ret
    }
}

Это очень простой тип. Обратите внимание, что вы должны объявить конструктор для ссылочного типа. В отличии от таких языков как C# и C++, ассемблер IL не будет генерировать для вас конструктор автоматически.

Типы задаются с помощью директивы .class, за которой следует заголовок типа. Ключевое слово class используется вместо более интуитивно понятного type в силу исторических причин. Когда вы встречаете в исходном MSIL-коде слово class, просто читайте его как type. Заголовок типа состоит из определённого количества аттрибутов, за которым следует имя типа, который вы определяете. Чтобы задать эквивалент статического класса C#, вы можете написать следующее:

.class abstract sealed Kerr.RealEstate.MortgageCalculator
{
    /* members */ 
}

abstract и sealed - это атрибуты типа. Нельзя сделать экземпляр абстрактного типа, а запечатанный (sealed) тип не может иметь подтипы. Есть атрибуты, которые служать для контроля видимости, такие как public и private. Есть атрибуты для контроля местоположения поля (field layout), такие как auto и sequential. Полный лист атрибутов можно узнать в спецификации CLI. Многие атрибуты применяются автоматически, что экономит на печати символов. К счастью, эти атрубты по умолчанию достаточно интуитивны, так что вы познакомитесь с ними достаточно быстро. Например, расширение System.ValueType из сборки mscorlib задаёт новый тип значений. Так как CLI требует, что типы значений были запечаны, ассемблер IL автоматически присвоит этот атрибут.

Имя типа в вышеприведённом примере было Kerr.RealEstate.MortgageCalculator. CLI не распознаёт пространства имён сами по себе, скорее речь идёт об использовании полного имени типа. Применённый выше синтаксис поддерживается ассемблером IL, который поставляется с .NET Framework версии 2.0. Если вы работаете с версией 1.x, тогда вам придётся применить директиву .namespace так. как это показано ниже. Обратите внимание, что этот синтаксис также поддерживается в версии 2.0.

.namespace Kerr.RealEstate
{
    .class abstract sealed MortgageCalculator
    {
        /* members */ 
    }
}

После имени типа у вас есть возможность задать базовый тип. Ключевое слово extend применяется именно с этой целью. Если базовый тип не задан, ассемблер IL автомтически сделает так, что тип будет наследоватья от System.Object из сборки mscorlib. И, наконец, в заголовке типа могут быть указан список интерфейсов, которые будут реализованы в типе и его потомках.

.class Kerr.RealEstate.RoomList
    extends [System.Windows.Forms]System.Windows.Forms.ListView
    implements Kerr.IView
{
    /* members */
}

В этом примере у типа Kerr.RealEstate.RoomList есть базовый тип System.Windows.Forms.ListView, заданный в сборке System.Windows.Forms. Помните, что CLI требует от каждого пользовательского типа расширять ровно один другой тип. Roomlisе также реализует интерфейсный тип Kerr.IView.

С помощью этого введения, вы теперь должны суметь задавать более интересные типы. Чтобы определить интерфейс, просто используйте атрибут interface в заголовке типа. Если вам нужен тип значения, известный в C# как struct, просто расширет тип System.ValueType из сборки mscorlib. Теперь вы видите, почему название директивы .class, возножно, далеко не самое лучшее.

.class interface Kerr.IView
{
    /* members */ 
}

.class Kerr.RealEstate.HouseData
    extends [mscorlib]System.ValueType
{
    /* members */
}

2002-2013 (c) wasm.ru