Clr common language runtime это

Обновлено: 01.07.2024

Спецификация CLI

Рис. 1.3. Существующие реализации CLI и поддерживаемые ими операционные системы
  • Общая система типов ( Common Type System , сокращенно CTS ) - охватывает большую часть типов, встречающихся в распространенных языках программирования.
  • Виртуальная система исполнения (Virtual Execution System, сокращенно VES) - отвечает за загрузку и выполнение программ, написанных для CLI.
  • Система метаданных ( Metadata System) - предназначена для описания типов, хранится в независимом от конкретного языка программирования виде, используется для передачи типовой информации между различными метаинструментами, а также между этими инструментами и VES.
  • Общий промежуточный язык (Common Intermediate Language , сокращенно CIL) - независимый от платформы объектно-ориентированный байт-код, выступающий в роли целевого языка для любого поддерживающего CLI компилятора.
  • Общая спецификация языков (Common Language Specification, сокращенно CLS ) - соглашение между разработчиками языков программирования и разработчиками библиотек классов, в котором определено подмножество CTS и набор правил. Если разработчики языка реализуют хотя бы определенное в этом соглашении подмножество CTS и при этом действуют в соответствии с указанными правилами, то пользователь языка получает возможность использовать любую соответствующую спецификации CLS библиотеку. То же самое верно и для разработчиков библиотек: если их библиотеки используют только определяемое в соглашении подмножество CTS и при этом написаны в соответствии с указанными правилами, то эти библиотеки можно использовать из любого соответствующего спецификации CLS языка.
JIT-компиляция

Ключевой особенностью выполнения программ в среде .NET является JIT -компиляция. Аббревиатура JIT расшифровывается как Just-In-Time, и термин JIT -компиляция можно перевести как компиляция программ "на лету". JIT -компиляция заключается в том, что CIL-код, находящийся в запускаемой сборке, тут же компилируется в машинный код, на который затем передается управление.

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

Сборка мусора

Одни из самых неприятных ошибок, которые портят жизнь программисту, это, безусловно, ошибки, связанные с управлением памятью. В таких языках, как C и C++, в которых управление памятью целиком возложено на программиста, львиная доля времени, затрачиваемого на отладку программы, приходится на борьбу с подобными ошибками.

Давайте перечислим типичные ошибки при управлении памятью (некоторые из них особенно усугубляются в том случае, если в программе существуют несколько указателей на один и тот же блок памяти):

  1. Преждевременное освобождение памяти (premature free).

Эта беда случается, если мы пытаемся использовать объект, память для которого была уже освобождена. Указатели на такие объекты называются висящими ( dangling pointers ), а обращение по этим указателям дает непредсказуемый результат.

Иногда бывает важно не перестараться и не освободить ненужный объект дважды.

Когда мы постоянно выделяем новые блоки памяти, но забываем освобождать блоки, ставшие ненужными, память в конце концов заканчивается.

При интенсивном выделении и освобождении памяти может возникнуть ситуация, когда непрерывный блок памяти определенного размера не может быть выделен, хотя суммарный объем свободной памяти вполне достаточен. Это происходит, если используемые блоки памяти чередуются со свободными блоками и размер любого из свободных блоков меньше, чем нам нужно. Проблема особенно критична в серверных приложениях, работающих в течение длительного времени.

В программах, работающих в среде .NET, все вышеперечисленные ошибки никогда не возникают, потому что эти программы используют реализованное в CLR автоматическое управление памятью , а именно - сборщик мусора. Если не вдаваться в излишние на данном этапе изучения .NET подробности, можно сказать, что работа сборщика мусора заключается в освобождении памяти, занятой ненужными объектами. При этом сборщик мусора также умеет "двигать" объекты в памяти, тем самым устраняя фрагментацию адресного пространства.

Все эти чудеса, которые творит сборщик мусора, возможны исключительно благодаря тому, что во время выполнения программы известны типы всех используемых в ней объектов. Другими словами, данные, с которыми работает программа, находятся под полным контролем среды выполнения и называются, соответственно, управляемыми данными (managed data).

Верификация кода

Это код, который не может быть обработан JIT -компилятором, то есть не может быть транслирован в машинный код.

Это код, который может быть представлен в виде машинного кода. При этом он может содержать вредоносные фрагменты (например, вирусы) или ошибки, способные нарушить работу не только программы, но и среды выполнения и даже операционной системы.

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

Верифицируемый код - это код, безопасность которого может быть строго доказана алгоритмом верификации, встроенным в CLR.

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

1. Компиляция исходного кода в Microsoft Intermediate Language (IL)

2. Компиляция IL в специфичный для платформы код с помощью CLR

Основной механизм CLR физически имеет вид библиотеки под названием mscoree.dll (и также называется общим механизмом выполнения исполняемого кода объектов — Common Object Runtime Execution Engine). При добавлении ссылки на сборку для ее использования загрузка библиотеки mscoree.dll осуществляется автоматически и затем, в свою очередь, приводит к загрузке требуемой сборки в память. Механизм исполняющей среды отвечает за выполнение целого ряда задач. Сначала, что наиболее важно, он отвечает за определение места расположения сборки и обнаружение запрашиваемого типа в двоичном файле за счет считывания содержащихся там метаданных. Затем он размещает тип в памяти, преобразует CIL-код в соответствующие платформе инструкции, производит любые необходимые проверки на предмет безопасности и после этого, наконец, непосредственно выполняет сам запрашиваемый программный код.

Механизм mscoree.dll

Использование байт-кода с четко определенным универсальным синтаксисом дает ряд существенных преимуществ:

Независимость от платформы

Повышение производительности

Хотя язык IL выше сравнивался с Java, все же IL на самом деле более гибкий, чем байт-код Java. Код IL всегда компилируется оперативно (Just-In-Time, JIT-компиляция), в то время как байт-код Java часто интерпретируется. Одним из недостатков Java было то, что во время выполнения программ процесс трансляции байт-кода Java в родной машинный код приводил к снижению производительности (за исключением самых последних версий, где Java компилируется оперативно (JIT) на некоторых платформах).

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

Это объясняет, почему можно рассчитывать на то, что выполнение управляемого кода IL будет почти настолько же быстрым, как и выполнение родного машинного кода. Однако это не объясняет того, почему Microsoft ожидает повышения производительности. Причина состоит в том, что поскольку финальная стадия компиляции происходит во время выполнения, JIT-компилятор на этот момент уже знает, на каком типе процессора будет запущена программа. А это значит, что он может оптимизировать финальный исполняемый код, используя инструкции конкретного машинного кода, предназначенные для конкретного процессора.

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

COM и COM+

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

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

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

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

Языковые компиляторы и программы предоставляют функции среды выполнения так, чтобы они были полезны и интуитивно понятны для разработчиков. Это означает, что некоторые средства среды выполнения могут быть заметными в одной среде больше, чем в другой. Характеристики среды выполнения зависят от используемых языковых компиляторов и программ. Например, разработчик Visual Basic при работе со средой CLR может заметить, что язык Visual Basic имеет больше средств объектно-ориентированного программирования, чем раньше. Среда выполнения предоставляет следующие преимущества:

возможность легко использовать компоненты, разработанные на других языках;

расширяемые типы, предоставляемые библиотекой классов;

языковые возможности (например, наследование, интерфейсы и перегрузку) для объектно-ориентированного программирования;

поддержку явной свободной потоковой обработки, позволяющую создавать масштабируемые многопотоковые приложения;

поддержку структурированной обработки исключений;

поддержку настраиваемых атрибутов;

использование делегатов вместо указателей на функции для повышения типобезопасности и уровня защиты. Подробнее о делегатах см. в разделе Система общих типов CTS.

Версии CLR

В качестве примера приведу текст программы, выводящий на экран возраст объекта:
исходный текст программы, чтобы было понятно:
using System;

namespace ConsoleApplication_Test_Csharp
public class SomeClass
int age;
public int GetAge()
age = 22;
return age;
>
>
public sealed class Program
<
public static void Main()
System. Console .Write( "My age is " );
SomeClass me = new SomeClass();
int myAge;
myAge = me.GetAge();
System. Console .WriteLine(myAge);
Console .ReadLine();
>

>
>

* This source code was highlighted with Source Code Highlighter .

И так приступим:

CLR (Common language runtime) — общеязыковая исполняющая среда. Она обеспечивает интеграцию языков и позволяет объектам благодаря стандартному набору типов и метаданным), созданным на одном языке, быть «равноправными гражданами» кода, написанного на другом.

Компилятор, помимо ассемблера IL создает полные метаданные.

Метаданные — набор из таблиц данных, описывающих то, что определено в модуле. Также есть таблицы, указывающие на что ссылается управляемый модуль (например, импортируемые типы и числа). Они расширяют возможности таких технологий как библиотеки типов и файлы языка описания интерфейсов (IDL). Метаданные всегда связаны с файлом с IL кодом, фактически они встроены в *.exe или *.dll.
Таким образом метаданные это таблицы, в которых есть поля, говорящие о том, что такой-то метод находится в таком-то файле и принадлежит такому-то типу(классу).
Вот как выглядят метаданные для моего примера (таблицы метаданных просто преобразованы в понятный вид с помощью дизассемблера ILdasm.exe. На самом деле это часть *.exe файла программы:

metadata

Разобравшись с основными понятиями, давайте посмотрим из чего же состоит тот самый управляемый модуль (или просто наш файл ConsoleApplication_Test_Csharp.exe, который выполняет вывод на экран возраста объекта):

И так, что же происходит, когда запускается впервые программа?
Сперва происходит анализ заголовка, чтобы узнать какой процесс запустить (32 или 64 разрядный). Затем загружается выбранная версия файла MSCorEE.dll ( C:\Windows\System32\MSCorEE.dll для 32разрядных процессоров)
После чего вызывается метод, расположенный MSCorEE.dll, который и инициализирует CLR, сборки и точку входа функции Main() нашей программы.

static void Main()
System. Console .WriteLine( "Hello " );
System. Console .WriteLine( "Goodbye" );
>

* This source code was highlighted with Source Code Highlighter .

Для выполнения какого-либо метода, например System.Console.WriteLine(«Hello „), IL должен быть преобразован в машинные команды (те самые нули и единицы) Этим занимается Jiter или just-in-time compiler.

Сперва, перед выполнением Main() среда CLR находит все объявленные типы (например тип Console).
Затем определяет методы, объединяя их в записи внутри единой “структуры» (по одному методу определенному в типе Console).
Записи содержат адреса, по которым можно найти реализации методов (т.е. те преобразования, которые выполняет метод).

Jit

При первом обращение к функции WriteLine вызывается JiT-compiler.
JiTer 'у известны вызываемый метод и тип, которым определен этот метод.
JiTer ищет в метаданных соответствующей сборки — реализацию кода метода (код реализации метода WriteLine(string str) ).
Затем, он проверяет и компилирует IL в машинный код (собственные команды), сохраняя его в динамической памяти.
После JIT Compiler возвращается к внутренней «структуре» данных типа (Console) и заменяет адрес вызываемого метода, на адрес блока памяти с исполняемыми процессорными командами.
После этого метод Main() обращается к методу WriteLine(string str) повторно. Т.к. код уже скомпилирован, обращение производится минуя JiT Compiler. Выполнив метод WriteLine(string str) управление возвращается методу Main().

Из описания следует, что «медленно» работает функция только в момент первого вызова, когда JIT переводит IL код в инструкции процессора. Во всех остальных случаях код уже находится в памяти и подставляется как оптимизированный для данного процессора. Однако если будет запущена еще одна программа в другом процессе, то Jiter будет вызван снова для того же метода. Для приложений выполняемых в х86 среде JIT генерируется 32-разрядные инструкции, в х64 или IA64 средах — соответственно 64-разрядные.

IL может быть оптимизирован, т.е. из него будут удалены IL — команды NOP (пустая команда). Для этого при компиляции нужно добавить параметры

Debug версия собирается с параметрами: /optimize -, /debug: full
Release версия собирается с параметрами: /optimize +, /debug: pdbonly

Чем же отличается управляемый код от неуправляемого?

Неуправляемый код компилируется для конкретного процессора и при вызове просто исполняется.

В управляемой среде компиляция производится в 2 этапа:

Взаимодействие с неуправляемым кодом:

— управляемый код может вызывать направляемую функцию из DLL посредствам P/Invoke (например CreateSemaphore из Kernel32.dll).
— управляемый код может использовать существующий COM-компонент (сервер).
— неуправляемый код может использовать управляемый тип (сервер). Можно реализовать COM — компоненты в управляемой среде и тогда не нужно вести подсчет ссылок интерфейсов.

Параметр /clr позволяет скомпилировать Visual С++ код в управляемые IL методы (кроме когда, содержащего команды с ассемблерными вставками ( __asm ), переменное число аргументов или встроенные процедуры ( __enable, _RetrurAddress )). Если этого сделать не получится, то код скомпилируется в стандартные х86 команды. Данные в случае IL кода не являются управляемыми (метаданные не создаются) и не отслеживаются сборщиком мусора (это касается С++ кода).

В дополнение хочу рассказать о системе типов CTS, принятой Microsoft.

— CTS поддерживает только единичное наследование (в отличие от С++)
— Все типы наследуются от System.Object (Object — имя типа, корень все остальных типов, System — пространство имен)

По спецификации CTS любой тип содержит 0 или более членов.

Поле — переменная, часть состояния объекта. Идентифицируются по имени и типу.
Метод — функция, выполняющая действие над объектом. Имеет имя, сигнатуру(число параметров, последовательность, типы параметров, возвр. значение функции) и модификаторы.
Свойство — в реализации выглядит как метод (get/set) а для вызывающей стороны как поле ( = ). Свойства позволяют типу, в котором они реализованы, проверить входные параметры и состояние объекта.
Событие — обеспечивает механизм взаимного уведомления объектов.

Public — метод доступен любому коду из любой сборки
Private — методы вызывается только внутри типа
Family (protected) — метод вызывается производными типами независимо от сборки
Assembly (internal) — метод вызывается любым кодом из той же сборки
Family or Assembly
(protected internal) — метод вызывается производными типами из любой сборки и + любыми типами из той же сборки.

CLS

Пример проверки на соответствие CLS

Атрибут [assembly: CLSCompliant(true)] заставляет компилятор обнаруживать любые доступные извне типы, содержащие конструкции, недопустимые в других языках.

  1. using System;
  2. [assembly: CLSCompliant( true )]
  3. namespace SomeLibrary
  4. // возникает предупреждение поскольку тип открытый
  5. public sealed class SomeLibraryType
  6. // тип, возвращаемый функцией не соответсвует CLS
  7. public UInt32 Abc()
  8. // идентификатор abc() отличается от предыдущего, только если
  9. // не выдерживается соответсвие
  10. public void abc()
  11. // ошибки нет, метод закрытый
  12. private UInt32 ABC()
  13. >
  14. >

Первое предупреждение: UInt32 Abc() возвращает целочисленное целое без знака. Visaul Basic, например, не работает с такими значениями.
Второе предупрждение: два открытых метода Abc() и abc() — одиноквые и отличаются лишь регистром букв и возвращаемым типом. VisualBasic не может вызывать оба метода.

Убрав public и оставив только sealed class SomeLibraryType оба предупреждения исчезнут. Так как SomeLibraryType по-умолчанию будет internal и не будет виден извне сборки.

Компонент Common Language Runtime, подробно рассматриваемый в данной статье, располагается над сервисами операционной системы, которая в настоящее время является операционной системой Windows, но в дальнейшем таковой может быть практически любая программная платформа. Основное назначение CLR - выполнение приложений, соблюдение всех программных зависимостей, управление памятью, обеспечение безопасности, интеграция с языками программирования и т.п. Среда выполнения обеспечивает множество сервисов, облегчающих создание и внедрение приложений, и существенно улучшает надежность последних.

Разработчики не взаимодействуют с Common Language Runtime напрямую - все сервисы предоставляются унифицированной библиотекой классов, которая располагается над CLR. Эта библиотека содержит более 1000 классов для решения различных программных задач - от взаимодействия с сервисами операционной системы до работы с данными и XML-документами.

Компонент Common Language Runtime

Компилируемый компилятором код для CLR называется управляемым кодом (managed code). Управляемый код пользуется преимуществами среды выполнения и помимо собственно кода содержит метаданные, которые создаются в процессе компиляции и содержат информацию о типах, членах и ссылках, используемых в коде. Метаданные используются средой выполнения:

  • для обнаружения классов;
  • загрузки классов;
  • генерации кода для конкретной платформы;
  • обеспечения безопасности.

Среда выполнения также следит за временем жизни объектов. В COM/COM+ с этой целью использовались специальные счетчики (reference counter); в CLR тоже используются счетчики, а удаление объектов из памяти происходит с помощью процесса, называемого сборкой мусора (garbage collection).

Common Language Runtime также задает общую систему типов, используемую всеми языками программирования. Это означает, например, что все языки программирования будут оперировать целочисленными данными или данными с плавающей точкой единого формата и единой длины, а представления строк тоже будут едиными для всех языков программирования. За счет единой системы типов достигается более простая интеграция компонентов и кода, написанных на разных языках программирования. В отличие от COM-технологии, также основанной на наборе стандартных типов, но представляемых в бинарном виде, CLR позволяет выполнять интеграцию кода (который может быть написан на различных языках программирования) в режиме дизайна, а не в режиме выполнения.

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

Исполняемые файлы и метаданные

А теперь более подробно остановимся на концепции метаданных. Начнем с того, что создадим примитивную программу на VB.NET. Эта консольная программа выводит строку "Running under .NET" на стандартное устройство вывода и завершает свое выполнение. Код этой программы таков:

Sub Main()
Console.WriteLine("Running under .NET")
End Sub
End Module

В результате компиляции мы получаем исполняемый файл CONS.EXE, который является файлом в формате COFF/PE с дополнительными секциями, содержащими информацию, необходимую для Common Language Runtime. Мы можем убедиться в этом, выполнив команду DUMPBIN:

dumpbin cons.exe /all

На листинге 1 приведен фрагмент дампа исполняемого файла (показаны только основные элементы).

После того как мы рассмотрели содержимое исполняемого файла, обратимся к той его секции, где размещаются код и метаданные.

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

Как видно из приведенного фрагмента дампа, в нем содержится вся необходимая информация о нашей программе. Первая инструкция на языке IL (.assembly) содержит указание на внешнюю сборку - mscorlib. Следующая инструкция также содержит ссылку на внешнюю сборку. Это будет набор классов для поддержки программ на Visual Basic, реализованный в сборке Microsoft, - Microsoft.VisualBasic. Далее идет инструкция, описывающая нашу программу (в виде сборки) и собственно код. Отметим, что нашей программе присвоен уникальный глобальный идентификатор (GUID).

Microsoft Intermediate Language

В вышеприведенном дампе намеренно пропущена важная часть - код на языке IL. Когда мы компилируем наш код, результатом этого процесса становится не код на языке, понятном конкретной платформе, а код на промежуточном языке, называемом Microsoft Intermediate Language (MSIL), который представляет собой набор инструкций, не зависящих от конкретного процессора. Ниже приведен IL-код нашего метода Main():

.method public static void Main() cil managed
<
.entrypoint
.custom instance void
[mscorlib]System.STAThreadAttribute. ctor() = ( 01 00 00 00 )
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Running under .NET"
IL_0005: call void
[mscorlib]System.Console::WriteLine(string)
IL_000a: ret
> // end of method Cons::Main

mscorlib
System
System.Design
System.Drawing
System.Windows.Forms

Интересно, что JIT-компилятор не выполняет компиляцию всего IL-кода при первом обращении к программе. Вместо этого каждый метод компилируется при первом обращении к нему, и, таким образом, неиспользуемый код не компилируется. Откомпилированный код хранится в памяти, а последующие обращения к программе выполняют уже откомпилированный код. Microsoft предоставляет специальный компилятор CLR Native Image Generator (NGEN), который выполняет компиляцию всего IL-кода и сохраняет результат на диске (рис. 4).

При рассказе о Common Language Runtime мы неоднократно использовали термин "сборка" (assembly). Сборка представляет собой коллекцию из одного или более файлов. Часто эти файлы содержат код, но в состав сборки могут также входить и графические изображения, и ресурсы, и другие бинарные данные, ассоциированные с кодом. Такие сборки называются статическими сборками, поскольку они хранятся на диске. Динамические сборки создаются во время выполнения программы и на диске обычно не сохраняются.

На рис. 6 показаны сборки, состоящие из одного и нескольких файлов.

Для просмотра манифеста сборки можно использовать утилиту ILDASM, о которой было сказано выше. На рис. 7, например, показан манифест для нашей тестовой программы.

Как видно из рисунка, манифест содержит следующую информацию о сборке:

  • имя сборки;
  • версию;
  • файлы в данной сборке;
  • сборки, используемые данной сборкой.

Помимо стандартных полей в манифесте могут присутствовать дополнительные поля, задаваемые программистами.

Global Assembly Cache

Утилита GACUtil также может использоваться для просмотра содержимого Download Cache, для установки и удаления сборок. Отметим, что GAC представляет собой специализированный каталог, располагаемый в C:\ WINNT\assembly (рис. 8).

В следующей части статьи мы рассмотрим последний компонент Common Language Runtime - Common Type System. (Дополнительная информация о Common Language Runtime имеется в спецификации Common Language Infrastructure, Partition 1. Concepts and Architecture на Web-сайте фирмы Microsoft.)

Читайте также: