Модель выполнения .NET. Промежуточный язык Microsoft (MSIL).
Промежуточный язык MSIL (Microsoft Intermediate Language)
Исходный код может быть создан на нескольких языках программирования. Код компилируется .NET-компилятором в промежуточный код, псевдокод, именуемый промежуточным языком Microsoft (Microsoft Intermediate Language – MSIL). MSIL содержит набор переносимых инструкций (команд), которые не зависят от типа процессора. По сути, он определяет переносимость ассемблера, хотя концептуально MSIL подобен байт-коду в Java, но это не одно и то же.
Итак, цель CLR-системы при выполнении приложения перевести промежуточный код в исполняемый код. И, тогда, любая программа, подвергнутая MSIL-компиляции, может быть выполнена в любой среде, где установлена CLR. В этом и состоит способность .NET добиваться переносимости программ.
Код на языке MSIL переводится в исполняемый код с помощью JIT[1]-компилятора, означающего выполнение точно к нужному времени. Это отражает факт компиляции кода только при необходимости, при этом совершенно не используется интерпретатор.
В результате компиляции помимо MSIL-кода образуются и метаданные, которые содержатся в том же файле, где хранится MSIL-код.
Генерация управляемого кода. Сборка.
Генерация управляемого кода. Сборка
В общем случае при написании С#-программы создается код, называемый управляемым. Управляемый код выполняется под управлением CLR-системы. Под неуправляемым кодом понимаются Windows-программы, созданные для появления среды .NET Framework (например, функции Win32API). Их код не выполнялся CLR-системой. Управляемые и неуправляемые коды могут работать вместе.
С помощью компилятора для платформы .NET создается модуль DLL или EXE, содержимое которого – так называемая сборка (assembly) на языке IL. Это новый формат исполняемых файлов.
Помимо инструкций IL, двоичные модули .NET содержат также метаданные, которые подробно описывают все типы, используемые в модуле и саму сборку. Эта часть метаданных называется манифестом (manifest). В манифесте содержится информация о текущей версии сборки, о поддерживаемом естественном языке (англ., русск.), а также список всех внешних сборок, которые потребуются для нормального выполнения.
В подавляющем большинстве случаев двоичный файл .NET и сборка – это одно и то же. Между ними существует отношение «один-к-одному» (чаще всего – это файл .DLL). В сборке из одного файла такой файл содержит и манифест, и метаданные, и инструкции IL.
В сборке из нескольких двоичных файлов каждый двоичный файл называется модулем (module). В таких сборках один из двоичных файлов должен содержать манифест (сценарий) сборки (в нем могут находиться и другие данные, в том числе инструкции IL). Все остальные модули могут содержать только метаданные типов и инструкции IL. Зачем может потребоваться создание многофайловой сборки? Одна из причин – большая гибкость при развертыванииприложения. Например, идет обращение к удаленной сборке, которая должна быть загружена на локальный компьютер. Среда загрузит лишь те модули сборки, которые действительно необходимы. Такое решение позволит избежать ненужного сетевого трафика и увеличить скорость работы программы.
7-8.Синтаксис языкаC#. Встроенные типы и системные типы.
Включение комментариев
При создании приложения хорошим тоном считается его полное документирование с включением комментариев в исходный текст программы. Поскольку комментарии не компилируются при их написании можно использовать кириллицу.
Строковые комментарии начинаются с комбинации символов // и завершаются с концом строки, в которой они размещены. Эти комментарии могут занимать всю строку или располагаться в конце строк, содержащих другую информацию. Если комментарий не может быть размещен на одной строке, то его можно оформить как последовательность строковых комментариев, или же поместить в специальные скобки. В последнем случае открывающая скобка комментария представляет собой комбинацию символов /*, а закрывающая скобка комментария – комбинацию символов */. Такие комментарии называются регулярными. Следует помнить о том, что скобки регулярных комментариев не допускают вложения, то есть текст, расположенный в этих скобках не может содержать комбинации символов */, поскольку это приведет к появлению неоднозначности.
Программные блоки
В языке C# описания типов, методов, свойств, синтаксические конструкции операторов ветвления и циклов образуют в тексте программные блоки. Программный блок – это последовательность операторов (возможно пустая), заключенная в фигурные скобки { }.
Объявление переменных. Если необходимо объявить несколько переменных или полей одного типа, то идентификаторы переменных можно перечислить через запятую после имени типа. При этом для каждой переменной можно выполнить начальную инициализацию.
int a; //Простейший вариант объявления
int a = 20; //Объявление с инициализацией
int a, b, c; //Объявление нескольких однотипных переменных
int a = 20, b = 10; //Объявление и инициализация переменных
Локальная переменная метода может быть объявлена в программном блоке. В этом случае время жизни переменной ограничено блоком:
{
int i = 10;
Console.WriteLine(i);
}
// ошибка компиляции – переменная i не доступна!!!
Console.WriteLine(i);
Если программные блоки вложены друг в друга, то внутренний блок не может содержать объявлений переменных, идентификаторы которых совпадают с переменными внешнего блока:
{
int i = 10;
{
//ошибка компиляции – i существует во внешнем блоке
int i = 20;
}
}
1.3. Система типов языка C#
Основой C# является развитая система типов. Проведем ее классификацию. С точки зрения размещения переменных в памяти все типы можно разделить на структурные типы и ссылочные типы. Переменная структурного типа содержит непосредственно данные и размещается в стеке. Переменная ссылочного типа, далее называемая объектом, содержит ссылку на данные, которые размещены в управляемой динамической памяти. Структурными типами являются встроенные типы, перечисления и структуры. Ссылочные типы – это классы, интерфейсы, массивы и делегаты.
Перечисления, структуры, классы, интерфейсы, массивы и делегаты составляют множество пользовательских типов. Элементы пользовательских типов должны быть описаны программистом при помощи особых синтаксических конструкций. Можно утверждать, что любая программа на языке C# представляет собой набор определенных пользовательских типов. Опишем функциональность, которой обладают пользовательские типы.
1. Класс – тип, поддерживающий всю функциональность объектно-ориентированного программирования, включая наследование и полиморфизм.
2. Структура – тип, обеспечивающий всю функциональность ООП, кроме наследования. Структура в C# очень похожа на класс, за исключением отсутствия поддержки наследования.
3. Интерфейс – абстрактный тип, реализуемый классами и структурами для обеспечения оговоренной функциональности.
4. Массив – пользовательский тип для представления набора значений некоторых (примитивных или пользовательских) типов.
5. Перечисление – тип, содержащий в качестве членов именованные целочисленные константы.
6. Делегат – пользовательский тип для представления ссылок на методы.
В .NET Framework сглажено различие между типами и классами. А именно, любой тип можно воспринимать как класс, который может быть связан с другими типами (классами) отношением наследования. Это позволяет рассматривать все типы .NET Framework (и языка C#) в виде иерархии классов. При этом существует базовый тип System.Object (в C# – тип object), являющийся общим предком всех типов. Все структурные типы наследуются от класса System.ValueType.
Встроенные типы данных C#. Итак, в C# все типы данных (как структурные, так и ссылочные) производятся от класса System.Object. В то время как CTS отвечает за определение типов, которые могут использоваться в различных языках .NET, для большинства языков было решено реализовать псевдонимы для этих типов. Например, 4-байтовое целочисленное значение представляется типом System.Int32,который определен в CTS. В С# для этого типа определен псевдоним int.Использование этих методик равноценно. Любой встроенный тип данных в C# – это всего лишь псевдоним для существующего типа, определенного в пространстве имен System.