Опубликован: 28.06.2006 | Уровень: специалист | Доступ: платный | ВУЗ: Московский государственный технический университет им. Н.Э. Баумана
Лекция 4:

Формат метаданных. Взаимодействие программных компонентов

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >

Взаимодействие компонентов в среде .NET

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

Во-первых, компилятор любого языка программирования, реализованного на платформе .NET, генерирует сборки, содержащие CIL-код и метаданные. При этом формат этих сборок определяется спецификацией CLI и не зависит от языка программирования.

Во-вторых, любая программа, работающая в среде .NET, использует общую систему типов CTS. Поэтому представление данных в памяти определяется CTS и не зависит от языка программирования, на котором написана программа.

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

Эти три особенности платформы .NET позволяют среде выполнения автоматически обеспечивать взаимодействие компонентов вне зависимости от того, на каком языке они написаны.

На рис. 2.12 изображена схема взаимодействия двух объектов на платформе .NET. Объекты Client и Server находятся в разных компонентах, работающих в адресном пространстве одного процесса (здесь мы не рассматриваем межпроцессное взаимодействие, а также взаимодействие по сети). Передача сообщения от объекта Client объекту Server сводится к простому вызову соответствующего метода объекта Server, то есть в среде .NET не нужны никакие объекты-заглушки.

Взаимодействия двух объектов в среде .NET

Рис. 2.12. Взаимодействия двух объектов в среде .NET

Компоненты на платформе .NET представляют собой сборки .NET. Сборка .NET может статически импортировать любую другую сборку и свободно использовать типы, экспортируемые из этой сборки. Для этого информация об импортируемой сборке заносится в таблицу метаданных AssemblyRef, информация о каждом импортируемом типе - в таблицу TypeRef, а информация о каждом импортируемом методе и поле - в таблицу MemberRef. Кроме того, сборка может импортироваться динамически через рефлексию (мы рассмотрим эту возможность в следующей лекции).

Видимость и контроль доступа

Метаданные в сборках .NET содержат полную информацию о типах. При этом каждый тип может экспортироваться или не экспортироваться из сборки, а каждый член типа (метод, поле, свойство и т.д.) должен быть объявлен с определенным значением флага доступа.

Видимость типа (т.е. экспортируется он из сборки или нет) определяется флагом видимости и хранится в поле Flags соответствующей этому типу записи в таблице метаданных TypeDef. В таблице 2.3 приведен набор флагов видимости для типов.

Таблица 2.3. Флаги видимости для типов
Флаг Значение Описание
NotPublic 0x00000000 Тип не экспортируется из сборки
Public 0x00000001 Тип экспортируется из сборки
NestedPublic 0x00000002 Вложенный тип доступен везде
NestedPrivate 0x00000003 Вложенный тип доступен только внутри того типа, в который он вложен
NestedFamily 0x00000004 Вложенный тип доступен наследникам того типа, в который он вложен
NestedAssembly 0x00000005 Вложенный тип доступен везде внутри сборки
NestedFamAndAssem 0x00000006 Вложенный тип доступен наследникам того типа, в который он вложен, но только внутри сборки
NestedFamOrAssem 0x00000007 Вложенный тип доступен везде внутри сборки, и, кроме того, наследникам того типа, в который он вложен

Доступ к методам, полям и свойствам типа определяется значением флага доступа. Описание допустимых значений приводится в таблице 2.4.

Таблица 2.4. Флаги доступа для членов типа
Флаг Значение Описание
CompilerControlled 0x00000000 Доступ контролируется компилятором
Private 0x00000001 Доступен только внутри типа
FamAndAssem 0x00000002 Доступен наследникам типа, объявленным внутри сборки
Assembly 0x00000003 Доступен только внутри сборки
Family 0x00000004 Доступен наследникам типа
FamOrAssem 0x00000005 Доступен внутри сборки, а также наследникам типа
Public 0x00000006 Доступен везде
Пример межъязыкового взаимодействия

Рассмотрим учебный пример, который представляет собой компонентную систему, написанную сразу на четырех языках. Диаграмма классов примера дана на рисунке 2.13.

Диаграмма классов учебного примера

Рис. 2.13. Диаграмма классов учебного примера

Абстрактный класс SortedArray реализован на Visual Basic .NET. В этом классе определено поле Arr, представляющее собой массив целых чисел. Конструктор класса SortedArray копирует в это поле массив, передаваемый ему в качестве параметра, а затем вызывает абстрактный метод Sort() для сортировки этого массива. Для доступа к отсортированному массиву используются свойства Array и Count:

Public MustInherit Class SortedArray
  Protected Arr() As Integer
  Protected MustOverride Sub Sort()
  Public Sub New(ByVal A() As Integer)
    Dim i As Integer
    Arr = New Integer(A.Length - 1) {}
    For i = 0 To A.Length - 1
      Arr(i) = A(i)
    Next
    Sort()
  End Sub
  Default Public ReadOnly Property 
    Array (ByVal Index As Integer) As Integer
    Get
      Return Arr(Index)
    End Get
  End Property
  Public ReadOnly Property Count() As Integer
    Get
      Return Arr.Length
    End Get
  End Property

End Class

Класс BubbleSortedArray написан на Visual C++ with Managed Extensions. Он переопределяет абстрактный метод Sort(), реализуя в нем пузырьковую сортировку:

using namespace VBLib;

public _ _gc class BubbleSortedArray: public SortedArray
{
protected:
  void Sort()
  {
    for (int i = Arr->Length, flag = 1; i > 1 && flag; i--)
    {
      flag = 0;
      for (int j = 0; j < i-1; j++)
        if (Arr[j] < Arr[j+1])
        {
          int tmp = Arr[j];
          Arr[j] = Arr[j+1];
          Arr[j+1] = tmp;
          flag = 1;
        }
    }
  }
public:
  BubbleSortedArray(int A _ _gc []): SortedArray(A) { }
};

Класс InsertSortedArray написан на Visual C#. Он переопределяет абстрактный метод Sort(), реализуя в нем сортировку вставками.

using VBLib;
public class InsertSortedArray: SortedArray
{
  protected override void Sort()
  {
    for (int i = 0; i < Arr.Length-1; i++)
    {
      int max = i;
      for (int j = i+1; j < Arr.Length; j++)
        if (Arr[j] > Arr[max])
          max = j;
      int tmp = Arr[i];
      Arr[i] = Arr[max];
      Arr[max] = tmp;
    }
  }
  public InsertSortedArray(int[] A): base(A) { }
}

И, наконец, все вышеперечисленные классы используются в программе, написанной на Visual J#.

package JsApp;
import VBLib.SortedArray;
public class Main
{
public static void main(String[] args)
{
    int A[] = new int[] { 5, 1, 6, 0, -4, 3 };
    SortedArray SA1 = new BubbleSortedArray(A),
          SA2 = new InsertSortedArray(A);
    for (int i = 0; i < SA1.get_Count(); i++)
      System.out.print(""+SA1.get_Array(i)+" ");
    System.out.println();
    for (int i = 0; i < SA2.get_Count(); i++)
      System.out.print(""+SA2.get_Array(i)+" ");
    System.out.println();
}
}

Общая спецификация языков

Различные языки программирования, которые уже реализованы или могут быть реализованы на платформе .NET, используют общую систему типов (CTS) в качестве модели данных. Общая система типов поддерживает все типы, с которыми работают распространенные в настоящее время языки программирования, но не каждый язык поддерживает все типы, реализованные в общей системе типов. Например, Visual Basic допускает типизированные ссылки в качестве параметров методов, и эти типизированные ссылки реализованы в общей системе типов, но C# их не понимает и, соответственно, не может использовать методы с такими параметрами.

Для того, чтобы любую библиотеку классов можно было использовать из любого языка платформы .NET, разработчики .NET придумали общую спецификацию языков (Common Language Specification - CLS).

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

В терминологии CLS библиотеки, соответствующие спецификации CLS, называются средами (frameworks), но мы будем называть их CLS-библиотеками. Компиляторы, генерирующие код, из которого можно получить доступ к CLS-библиотекам, называются потребителями (consumers). Компиляторы, которые являются потребителями, но, к тому же, способны создавать новые CLS-библиотеки, называются расширителями (extenders).

Приведем основные правила общей спецификации языков:

  1. Спецификация распространяется только на доступные извне части экспортируемых из библиотеки типов. То, что остается внутри библиотеки, может использовать любые типы, не оглядываясь на спецификацию.
  2. Упакованные типы-значения, неуправляемые указатели и типизированные ссылки не должны использоваться. Дело в том, что отнюдь не во всех языках, реализованных на платформе .NET, есть соответствующие понятия, и, более того, добавление этих понятий во все языки представляется нецелесообразным.
  3. Регистр букв в идентификаторах не имеет значения. Это правило объясняется тем, что в некоторых языках программирования (например, в Паскале) регистр букв не различается.
  4. Методы не должны иметь переменного количества параметров.
  5. Глобальные поля и методы не поддерживаются спецификацией.
  6. Объекты исключений должны наследовать от System.Exception.
< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Анастасия Булинкова
Анастасия Булинкова
Рабочим названием платформы .NET было
Bogdan Drumov
Bogdan Drumov
Молдова, Республика
Azamat Nurmanbetov
Azamat Nurmanbetov
Киргизия, Bishkek