Общеязыковая исполняющая среда CLR 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Общеязыковая исполняющая среда CLR



 

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

Центральной частью каркаса.NET является его общеязыковая исполняющая среда, известная как Common Language Runtime (CLR) или .NET runtime. Код, выполняемый под управлением CLR, часто называют управляемым кодом. С точки зрения программирования под термином исполняющая среда может пониматься коллекция внешних служб, которые требуются для выполнения скомпилированной единицы программного кода. Например, при использовании платформы MFC (Microsoft Foundation Classes) для создания нового приложения разработчики осознают, что их программе требуется библиотека времени выполнения MFC (т.е. mfc42.dll). Другие популярные языки тоже имеют свою исполняющую среду: программисты, использующие язык VB6, к примеру, вынуждены привязываться к одному или двум модулям исполняющей среды (вроде msvbvm60.dll), а разработчики на Java — к виртуальной машине Java (JVM).

В составе.NET предлагается ещё одна исполняющая среда. Главное отличие между исполняющей средой.NET и упомянутыми выше средами, состоит в том, что исполняющая среда.NET обеспечивает единый чётко определённый уровень выполнения, который способны использовать все совместимые с.NET языки и платформы.

Однако перед тем как код сможет выполняться CLR, любой исходный текст (на С# или другом языке) должен быть скомпилирован. Компиляция в.NET состоит из двух шагов:

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

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

Этот двух шаговый процесс компиляции очень важен, потому что наличие Microsoft Intermediate Language (IL) является ключом ко многим преимуществам.NET. Microsoft Intermediate Language (промежуточный язык Microsoft) разделяет с байт-кодом Java идею низкоуровневого языка с простым синтаксисом (основанным на числовых, а не текстовых кодах), который может быть очень быстро транслирован в родной машинный код.

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

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

Рис. 1. 1. Взаимоотношение исходного кода, компилятором.NET и механизмом выполнения.NET

 

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

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

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

Первым делом, это значит, что файл, содержащий инструкции байт-кода, может быть размещен на любой платформе; во время выполнения может быть легко проведена финальная стадия компиляции, что позволит выполнить код на конкретной платформе. Другими словами, компилируя в IL, разработчик получает платформенную независимость.NET — во многом так же, как компиляция в байт-код Java обеспечивает независимость от платформы программам на Java.

Следует отметить, что независимость.NET от платформы в настоящее время является лишь теоретической, поскольку реализация.NET доступна только для ОС Windows. Однако уже существуют частичные реализации для других платформ (например, проект Mono — попытка создать реализацию.NET с открытым кодом).

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

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

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

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

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

3. COM и COM+.

Формально СОМ и СОМ+ не являются технологиями, нацеленными на.NET, поскольку компоненты, основанные на них, не могут компилироваться в IL (хотя в определенной степени это и можно сделать, применяя управляемый С++, если исходный компонент СОМ+ был написан на С++). Однако СОМ+ остается важным инструментом, потому что его средства не дублируют.NET. К тому же компоненты СОМ будут по-прежнему работать, и.NET включает средства взаимодействия с СОМ, позволяющие управляемому коду вызывать компоненты СОМ и наоборот. Тем не менее, скорее всего, в большинстве случаев удобнее кодировать новые компоненты в виде компонентов.NET, чтобы воспользоваться преимуществами базовых классов.NET, а также другими выгодами от запуска управляемого кода.

Общая система типов CTS

Общая система типов CTS

 

Общая система типов CTS

 

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

CTS (Common Type Systemобщая система типов) представляет собой формальную спецификацию, в которой описано то, как должны быть определены типы для того, чтобы они могли обслуживаться в CLR-среде. Внутренние детали CTS обычно интересуют только тех, кто занимается разработкой инструментов и/или компиляторов для платформы.NET. Т.е. CTS описывает не просто примитивные типы данных, а целую развитую иерархию типов, включающую хорошо определенные точки, в которых код может определять свои собственные типы. Иерархическая структура общей системы типов (CTS) отражает объектно-ориентированную методологию одиночного наследования IL и показана на следующей схеме:

 

Рис. 1. 1. Общая система типов

 

Абсолютно всем.NET-программистам важно уметь работать на предпочитаемом ими языке с пятью типами из CTS. Краткий обзор этих типов приведен ниже:

1. Типы классов.

В каждом совместимом с.NET языке поддерживается, как минимум, понятие типа класса ( class type ), которое играет центральную роль в объектно-ориентированном программировании. Каждый класс может включать в себя любое количество членов(таких как конструкторы, свойства, методы и события) и точек данных (полей). В С# классы объявляются с помощью ключевого слова class:

 

class mySum

{

public int Sum(int x, int y)

{

return x + y;

}

}

 

Рассмотрим основные характеристики классов CTS:

 

Характеристика классов Описание
Запечатанные Запечатанные (sealed), или герметизированные, классы не могут выступать в роли базовых для других классов, т.е. не допускают наследования
Реализующие интерфейсы Интерфейсом (interface) называется коллекция абстрактных членов, которые обеспечивают возможность взаимодействия между объектом и пользователем этого объекта. CTS позволяет реализовать в классе любое количество интерфейсов
Абстрактные или конкретные Экземпляры абстрактных (abstract) классов не могут создаваться напрямую, и предназначены для определения общих аспектов поведения для производных типов. Экземпляры же конкретных (concrete) классов могут создаваться напрямую
Степень видимости Каждый класс должен конфигурироваться с атрибутомвидимости (visibility). По сути, этот атрибут указывает, должен ли класс быть доступным для использования внешним сборкам или только изнутри определяющей сборки

 

2. Типы интерфейсов.

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

 

// Объявление интерфейса в C#

public interface ICommandSource

{

void CommandParameter();

}

 

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

3. Типы структур.

Понятие структуры тоже сформулировано в CTS. Тем, кому приходилось работать с языком С, будет приятно узнать, что таким пользовательским типам удалось «выжить» в мире.NET (хотя на внутреннем уровне они и ведут себя несколько иначе). Попросту говоря, структура может считаться «облегчённым» типом класса с основанной на использовании значений семантикой. Обычно структуры лучше всего подходят для моделирования геометрических и математических данных, и в С# они создаются с помощью ключевого слова struct:

 

// Тип структуры в C#

struct Rectangle

{

// В структурах могут содержаться поля, конструкторы и определяться методы

public string recFill;

 

public void MyBackground()

{

Console.WriteLine("Фон элемента: " + recFill);

}

}

 

4. Типы перечислений.

Перечисления(enumeration) представляют собой удобную программную конструкцию, которая позволяет группировать данные в пары «имя-значение». Например, предположим, что требуется создать приложение видеоигры, в котором игроку бы позволялось выбирать персонажа одной из трех следующих категорий: «Wizard» (маг), «Fighter» (воин) или «Thief» (вор). Вместо того чтобы использовать и отслеживать числовые значения для каждого варианта, в этом случае гораздо удобнее создать соответствующее перечисление с помощью ключевого слова enum:

 

// Тип перечисления С#.

public enum CharacterType

{

Wizard = 100,

Fighter = 200,

Thief = 300

}

 

По умолчанию для хранения каждого элемента выделяется блок памяти, соответствующий 32-битному целому, однако при необходимости (например, при программировании с расчетом на устройства, обладающие малыми объемами памяти, вроде мобильных устройств на Windows Phone 7 и более старых Windows Mobile 6.x и ниже) это значение можно изменить. Кроме того, в CTS необходимо, чтобы перечисляемые типы наследовались от общего базового класса System.Enum. В этом базовом классе присутствует ряд весьма интересных членов, которые позволяют извлекать, манипулировать и преобразовывать базовые пары «имя-значение» программным образом.

5. Типы делегатов.

Делегаты (delegate) являются.NET-эквивалентом безопасных в отношении типов указателей функций в стиле С. Главное отличие заключается в том, что делегат в.NET представляет собой класс, который наследуется от System.MulticastDelegate, а не просто указатель на какой-то конкретный адрес в памяти. В С# делегаты объявляются с помощью ключевого слова delegate.

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

 

Члены типов

 

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

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

 

Встроенные типы данных

 

И, наконец, последним, что следует знать о спецификации CTS, является то, что в ней содержится четко определенный набор фундаментальных типов данных. Хотя в каждом отдельно взятом языке для объявления того или иного встроенного типа данных из CTS обычно предусмотрено свое уникальное ключевое слово, все эти ключевые слова в конечном итоге соответствуют одному и тому же типу в сборке mscorlib.dll.

 

В следующей таблице показано, как ключевые типы данных из CTS представляются в C#:

 

Типы данных в CTS Ключевое слово в C#
System.Byte byte
System.SByte sbyte
System.Int16 short
System.Int32 int
System.Int64 long
System.UInt16 ushort
System.UInt32 uint
System.UInt64 ulong
System.Single float
System.Double double
System.Object object
System.Char char
System.String String
System.Boolean bool

 

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



Поделиться:


Последнее изменение этой страницы: 2016-08-15; просмотров: 849; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.15.156.140 (0.058 с.)