Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Троелсен Э. Язык программирования С# 2010 и п...docx
Скачиваний:
112
Добавлен:
21.09.2019
Размер:
6.92 Mб
Скачать

Одномодульные и многомодульные компоновочные блоки

Во многих случаях компоновочные блоки .NET- это просто файлы двоичного кода (*.dll или *.exe). Поэтому, если вы строите *.dll .NET, можно считать, что файл двоичного кода и компоновочный блок – это одно и то же. Точно также, если вы строите выполняемое приложение для настольной системы, файл *.exe тоже можно считать компоновочным блоком. Но из главы 11 вы узнаете, что указанное соответствие не столь однозначно. Строго говоря, если компоновочный блок состоит из одного модуля *.dll или *.exe, вы имеете одномодульный компоновочный блок. Одномодульный компоновочный блок содержит весь необходимый код CIL, метаданные и манифест в одном автономном отдельном пакете.

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

Но зачем создавать многомодульные компоновочные блоки? Когда вы делите компоновочный блок на отдельные модули, вы получаете более гибкие возможности инсталляции. Например, если пользователь ссылается на удаленный компоновочный блок, то среда выполнения загрузит на его машину только необходимые модули. Поэтому вы можете сконструировать свой компоновочный блок так, чтобы редко используемые типы (например, HardDriveReformatter) были выделены в отдельный автономный модуль.

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

Роль cil

Теперь, когда вы имеете начальное представление о компоновочных блоках .NET, давайте немного подробнее обсудим роль общего промежуточного языка (CIL). CIL- это язык, находящийся выше любого набора инструкций, специфического для конкретной платформы. Независимо от того, какой язык .NET вы выберете для использования, соответствующий компилятор сгенерирует инструкции CIL. Например, следующий программный код C# моделирует тривиальный калькулятор. Не пытаясь пока что полностью понять синтаксис этого примера, обратите внимание на формат метода Add() в классе Calc.

// Calc.cs

using System;

namespace CalculatorExample {

 // Этот класс содержит точку входа приложения.

 public class CalcApp {

  static void Main() {

   Calc с = new Calc();

   int ans = c.Add(10, 84);

   Console.WriteLine("10 + 84 is {0}.", ans);

   // Ждать, пока пользователь не нажмет клавишу ввода.

   Console.ReadLine();

  }

 }

 // C#-калькулятор.

 public class Calc {

  public int Add(int x, int y) {return x + y;}

 }

}

После того как компилятор C# (csc.exe) скомпилирует этот файл исходного кода, вы получите состоящий из одного файла компоновочный блок *.exe, который содержит манифест, CIL-инструкции и метаданные, описывающие каждый аспект классов Calc и CalcApp. Например, если вы откроете этот компоновочный блок с помощью ildasm.exe (мы рассмотрим ildasm.exe немного позже в этой же главе), вы увидите, что метод Add () в терминах CIL представляется так.

.method public hidebysig instance int32 Add(int32 x, int32 y) cil managed

{

 // Code size 8 (0x8)

 .maxstack 2

 .locals init ([0] int32 CS$l$0000)

 IL_0000: ldarg.1

 IL_0001: ldarg.2

 IL_0002: add

 IL_0003: stloc.0

 IL_0004: br.s IL_0006

 IL_0006: ldloc.0

 IL_0007: ret

} // end of method Calc::Add

Не беспокойтесь, если вы пока не в состоянии понять CIL-код для этого метода – в главе 15 будут описаны основы языка программирования CIL. Здесь следует сконцентрироваться на том, что компилятор C# генерирует CIL-код, а не специфические для платформы инструкции.

Напомним теперь, что это верно для всех .NET-компиляторов. Для иллюстрации предположим, что вы создали аналогичное приложение с помощью Visual Basic .NET (VB .NET), а не с помощью C#.

' Calc.vb

Imports System

Namespace CalculatorExample

 ' VB .NET 'Модуль' – это класс, содержащий только ' статические члены.

 Module CalcApp

  Sub Main()

   Dim ans As Integer

   Dim с As New Calc

   ans = c.Add(10, 84)

   Console.WriteLine("10 + 84 is {0}.", ans)

   Console.ReadLine()

  End Sub

 End Module

 Class Calc

  Public Function Add(ByVal x As Integer, ByVal у As Integer) As Integer

   Return x + у

  End Function

 End Class

End Namespace

Если теперь проверить CIL-код для метода Add(), вы обнаружите подобные инструкции (слегка "подправленные" компилятором VB .NET).

.method public instance int32 Add(int32 x, int32 y) cil managed

{

 // Code size 9 (0x9)

 .maxstack 2

 .locals init ([0] int32 Add)

 IL_0000: nop

 IL_0001: ldarg.1

 IL_0002: ldarg.2

 IL_0003: add.ovf

 IL_0004: stloc.0

 IL_0005: br.s IL_0007

 IL_0007: ldloc.0

 IL_0008: ret

} // end of method Calc::Add