|
Архитектура
.NET (обзор)
Оригинал
статьи Автор: Илья Хейфец AGAVA Software Company
Введение
.NET платформа упрощает
разработку приложений и повышает надежность кода. В частности, она
обеспечивает автоматическое управление временем жизни объектов,
нейтральные к языкам библиотеки классов и пересекающие границы языков
наследование, обработку исключений и отладку.
Архитектура
.NET изображена на рисунке.
[Рисунок взят с сайта
Microsoft.]
Common Language Runtime
опирается на системные сервисы операционной системы и управляет
выполнением кода, написанного на любом современном языке программирования.
Набор базовых классов дает доступ к сервисам платформы, которые
разработчики могут использовать из любого языка программирования. Common
Language Runtime и базовые классы вместе составляют основу .NET платформы.
Эта архитектура очень похожа на архитектуру C runtime, Visual Basic
runtime или виртуальной машины Java.
.NET предлагает также
высокоуровневые сервисы: - ADO+ - новое поколение ADO, которое
использует XML и SOAP для обмена данными - ASP+ - новая версия ASP,
позволяющая использовать любой (.NET совместимый) язык для
программирования Web страниц - Win Forms и Web Forms – набор классов
для построениения пользовательского интерфейса локальных и
Web-ориентированны приложений. Отдельно упомянем C# (произносится «си
шарп») - новый объектно-ориентированный язык, нацеленный на создание
приложений для платформы .NET.
Common Language Runtime
(CLR)
CLR предоставляет исполняемому
коду определенный набор сервисов. Например, CLR поддерживает создание и
манипулирование потоками. Поэтому любой язык, который может использовать
CLR, сможет использовать потоки. Код, который нуждается в CLR во
время выполнения, называется “управляемый” (managed) код. Ответственность
за такие задачи как создание объектов и вызов методов возлагается на CLR.
Код, который не нуждается в CLR, называется “неуправляемый” (unmanaged)
код.
Microsoft предоставляет 4
компилятора, которые генерируют код для .NET CLR: C++, C#, Visual Basic
(включая VBScript и Visual Basic for Applications) и JScript. Visual C++ -
это единственный компилятор, который может генерировать неуправляемый код.
Остальные компиляторы могут производить только управляемый код, и поэтому
код, написанный на этих языках, всегда нуждается в CLR. Несколько компаний
также производят компиляторы управляемого кода. Например, Rational
планирует создать такой компилятор для Java. Рассмотрим основные понятия
.NET и сервисы CLR
Автоматическое управление
ресурсами
Одна из наиболее частых ошибок
заключается в том, что приложение не освобождает ресурсы или пытается их
использовать после освобождения. CLR автоматически отслеживает
использование ресурсов, гарантируя их своевременное освобождение.
Выполнение на многих
платформах
Сегодня имеются много различных
версий Windows. Написаное и собранное управляемое .NET приложение сможет
выполняться на любой платформе, которая поддерживает .NET CLR.
Согласующаяся модель
программирования
Модель программирования .NET
упрощает конструкции Win32 и COM. Программисты больше не должны заботится
о деталях реестра, GUID, IUnknown, AddRef, Release, HRESULTS и тому
подобного. .NET не просто инкапсулирует эти понятия; на новой платформе
они вовсе отсутствуют. Отметим также, что в .NET все сообщения об
ошибках передаются единым способом: через исключения.
Контроль типов
.NET CLR конролирует доступ к
объектам и гарантирует, что доступ производится в соответствии с типом
этих объектов. Также CLR не позволит создать указатель на произвольный
адрес в памяти и выполнить код по этому адресу. Это, в частности,
исключает возникновение множества типичных ошибок программирования и
классических атак по методу переполнения буфера.
Интеграция языков
COM позволяет взаимодействовать
компонентам на различных языках программирования. .NET интегрирует языки
друг с другом. Например, можно создать Си++ класс, который наследует
классу, реализованному на Visual Basic. Это означает, что программисты,
использующие библиотеку классов, больше не ограничены в выборе языка
языком этой библиотеки. Исключение может быть вызвано из кода, написанного
на одном языке и обработано в коде, написанном на другом языке. Операции
отладки и профилирования (profiling) работают, плавно пересекая границы
языков. Такая интеграция становится возможной, поскольку .NET определяет и
предоставляет систему типов, общую для всех языков.
Общая система типов (Common
Type System)
Формальная спецификация системы
типов, реализованной CLR, называется Common Type System (CTS). Основная
задача системы типов – обеспечение интеграции языков.
Чтобы писать управляемый код не
нужно знать правила CTS, поскольку выбранный язык предоставит собственный
синтаксис и правила типов и отобразит свой синтаксис в синтаксис CLR в
процессе компиляции. Например, CTS поддерживает только одиночное
наследование, а Cи++ поддерживает классы, которые наследуют от нескольких
базовых классов. Чтобы помочь разработчикам, компилятор Visual C++ сообщит
об ошибке, если заметит, что вы пытаетесь использовать множественное
наследование в управляемом коде.
Еще одно правило CTS гласит, что
все базовые классы должны наследовать классу System.Object. Object – это
имя типа, определенного в пространстве имен System. (Более подробно
базовые классы описываются ниже).
Assemblies - управляемые
компоненты
[assembly – новый термин,
который раньше употреблялся только в отношении языка ассемблера. По сути
это «пакет» или «комплект», но я думаю, что лучше или оставить английское
написание, или перевести как асембл (по аналогии со словом stub, которое
сейчас правильно переводится как «стаб», а раньше пытались переводить как
«заглушка»). Но managed я перевел как «управляемый», поскольку вряд ли
приживется слово «менеджед». CLR тоже сложно переводить.]
.NET использует новую модель
расположения приложений, которая упрощает инсталляцию и отслеживание
версий. Ключевое понятие этой модели – асембл (assembly).
Assembly – это набор ресурсов и типов, а также метаданные, описывающие
типы и методы, реализованные assembly. Т.о. assembly – это самоописанный
компонент. Основное преимущество таких компонентов в том, что для их
использования не нужны никакие другие файлы. Заголовочные файлы, IDL
файлы, библиотеки типов и прокси-стабы не требуются, чтобы получить доступ
к компоненту из любого языка - необходимая информация заключена в
метаданных компонента.
Assemblies могут принадлежать
одному приложению или разделяться между несколькими приложениями. CLR
может загружать различные версии одного assembly для двух различных
приложений, которые выполняются одновременно. Поскольку assembly
самоописаны, никакая их регистрация в операционной системой не требуется и
инсталляция приложения представляет простое копирование файлов.
Assemblies также играют роль в .NET системе безопасности, где assembly
является единицей, на которую запрашиваются и предоставляются
разрешения.
Система безопасности
CLR предоставляет сервисы
безопасности, контролирующие доступ пользователей к ресурсам и действия
программ. Поскольку CLR используется, чтобы загружать код, создавать
объекты и вызывать методы, он может управлять безопасностью и предписывать
политики безопасности. Обеспечение безопасности в .NET возможно на двух
уровнях: на уровне кода (code access security) и на уровне ролей
пользователей (role-based security).
Программисты определяют
требуемые привилегии, которые должен иметь код для выполнения работы.
Например, код нуждается в разрешении, чтобы писать в файл или читать
переменные среды. Эта информация хранится в assembly, наряду с информацией
относительно подлинности кода. Политики для предоставления разрешений
устанавливаются администраторами системы на основании данных относительно
происхождения кода и прочих. Разрешения могут выдаваться также исходя из
данных пользователя. Роли представляют собой категории пользователей и
могут быть определены во время разработки или в процессе инсталляции.
Промежуточный Язык и JIT
компилятор
Когда файлы с исходными текстами
готовы, вы запускаете компилятор и получаете EXE или DLL. Эти EXE или DLL
файлы очень похожи на PE (Portable Executable – портируемые выполняемые)
файлы, по сути дела они и есть PE файлы с некоторыми отличиями.
Первое отличие заключается в
том, что код в управляемых PE файлах не является командами процессора x86
или другим машинным кодом. Вместо этого компилятор создает код на
Промежуточном Языке Microsoft (Microsoft intermediate language - MSIL). PE
файл, содержащий MSIL может выполняться на платформе любого процессора,
если операционная система, предоставляет .NET CLR.
Второе отличие заключается в
том, что этот файл содержит метаданные, которые используются CLR для
обнаружения и загрузки типов из файла, разположения объектов в памяти,
вызова методов, управления ссылками, перевода MSIL в машинные коды,
контроля за безопасностью и множества других задач.
Еще одно отличие – то что
полученные компоненты не просто EXE или DLL файлы. Единица использования и
размещения в .NET – это assembly. В зависимости от опций компилятора можно
получить однофайловый assembly или модуль с управляемым кодом,
распространяемый как часть многофайлового assembly. С точки зрения
клиента, assembly – это именованная коллеция экспортируемых типов и
ресурсов. С точки же зрения разработчика assembly, – это коллекция PE
файлов, файлов ресурсов, HTML страниц, картинок и т.п.
MSIL – это процессоронезависимый
промежуточный язык, созданный Microsoft. MSIL - язык более высокого
уровня, чем большинство машинных языков. Он понимает типы объектов и имеет
инструкции для создания и инициализации объектов, вызова виртуальных
методы и непосредственной манипуляции элементами массива. Он даже имеет
инструкции, которые оперируют исключениями. Как и любой другой машинный
язык, MSIL может быть написан на ассемблере. Microsoft предоставляет
ассемблер и дизассемблер для MSIL.
Когда вы собираете управляемую
программу, модуль импортирует функцию _CorExeMain из .NET CLR
(MSCorEE.dll). Когда пользователь запускает программу, загрузчик
операционной системы переходит к точке входа внутри выполняемого блока.
Код в выполняемом блоке просто передает управление функции _CorExeMain,
содержащейся внутри MSCorEE.dll. CLR находит точку входа управляемого
модуля и затем начинает выполнять управляемый код MSIL выполняемого
блока.
Перед тем, как выполнять
управляемый код CLR должен сначала скомпилировать управляемые MSIL
инструкции в инструкции процессора. Здесь возникает типичная проблема:
когда пользователь запускает программу, он не намерен ждать пока вся
программа скомпилируется, тем более, что большинство функций программы не
будут вызваны. Поэтому CLR, компилирует MSIL код в инструкции процессора,
когда функции непосредственно вызваны. Всякий раз, когда такая функция
вызывается в будущем, сразу выполняется машинный код (а компилятор уже не
вовлекается в процесс). Поскольку MSIL компилируется только в нужный
момент (just-in-time - JIT), этот компонент CLR часто упоминается как JIT
компилятор (JIT compiler) или JITter.
(картинка с сайта Microsoft)
(Перевод: исходный код->
компилятор -> exe/dll (IL и метаданные) –> загрузчик класса ->
JIT компилятор с необязательной проверкой -> машинные коды ->
выполнение -> проверки безопасности; runtime engine; Библиотеки класов
(IL и метаданные); безопасный прекомпилированный код; вызов
некомпилированного метода)
Программисты на низкоуровневых
языках типа C или Cи++ возможно думают об эффективности выполнения
описанной схемы. Ведь неуправляемый код компилируется сразу в инструкции
процессора и при вызове просто выполняется. А в управляемом окружении
чтобы выполнить код, MSIL должен компилироваться в инструкции процессора в
реальном времени, потребляя большое количество памяти и мощности
процессора.
Действительно, управляемый код
выполняется медленнее и имеет больше накладных расходов, чем неуправляемый
код. Но Microsoft предлагает инструмент, позволяющий выполнять полную
компиляцию assembly в машинные коды и сохранять результат на диске. Когда
assembly загрузится в следующий раз, будет использована эта сохраненная
версия и приложение стартует быстрее.
Отметим особо, что в приложении
можно совмещать фрагменты управляемого и неуправляемого кода.
Неуправляемый код следует использовать для критичных к времени выполнения
функций.
Базовые классы
Над CLR в архитектуре .NET
находится инфраструктура сервисов (services framework). Эта инфраструктура
предоставляет классы, которые могут быть использованы из любого языка
программирования. Каждый класс дает доступ к некоторому элементу основной
платформы.
Для примера приведем несколько
пространств имен (namespaces) и их классы.
Пространство имен |
Назначение содержащихся классов |
Пример классов |
System |
Реализация типов, используемых каждым
приложением |
Object, Byte, Array, Int32, Exception,
String |
System.Collections |
Управление наборами данных |
ArrayList, Dictionary, Hashtable,
Queue |
System.Data |
Работа с базами данных |
DataBinding, DataTable,
DataSource |
System.IO |
Чтение и запись |
ByteStream, File, FileStream,
MemoryStream |
System.Net |
Сетевые взаимодействия |
WebRequest, UdpClient, Sockets |
System.Web.UI.WebControls |
Построение пользовательского интерфейса
для приложений, ориентированных на Web |
DataGrid, HyperLink, ListBox,
RadioButton, Table |
System.WinForms |
Построение пользовательского интерфейса
для локальных приложений |
Button, CheckBox, DataGrid, FileDialog,
ListBox, MainMenu |
Имеются также классы для
рисования (GDI+), работы с потоками, национальной поддержки, криптографии,
сериализации, и т.д. Также есть, например, классы, предназначенные для
инструментов разработки и позволяющие выполнять такие функции как
отладка-трассировка, создание ресурсов, конфигурирование-инсталляция,
получение лога событий и оценка эффективности. Методы класса могут быть
перегружены, поэтому методы, отличающиеся лишь немного по поведению, имеют
идентичные имена и различается только прототипами. Например, класс может
предлагать три различных версии метода CreatePen с разными наборами
параметров.
.NET - полностью
объектно-ориентированная платформа. Программисты могут создавать
собственные пространства имен, содержащие их собственные классы. Это
значительно упрощает разработку программного обеспечения по сравнению с
классическими Windows парадигмами программирования. Так как все услуги
платформы предлагаются через объектно-ориентированную парадигму,
разработчики должны иметь некоторое понимание объектно-ориентированного
программирования.
С#
С# вобрал в себя все лучшее из
таких популярных языков как Си++, Visual Basic, Java и Object Pascal. С#
обеспечивает быструю разработку, в то же время позволяет писать
эффективный код. Перечислим особенности нового языка: - автоматическая
уборка мусора - возможность манипулировать указателями и иметь
непосредственный доступ к памяти - поддержка свойств и событий
(аналогично VB) - поддержка атрибутов - встроенная поддержка
основных типов (строка, массив, ...) - множественное наследование
возможно только от интерфейсов (как в Java) - поддержка С API, Windows
API и COM+ на уровне языка - поддержка assembly - контроль
типов - автоматическая инициализация переменных
Атрибуты являются новым
механизмом. С их помощью можно ввести новые типы описательной информации
для классов и методов и получать эту информацию во время выполнения.
Единственное чего не хватает в новом языке – это шаблонов, так
полюбившихся программистам на Си++ за последние несколько лет. Приведем
код традиционной прграммы «Hello, world»
using System; class Hello { static void
Main() { Console.WriteLine("Hello,
world"); } }
Как можно заметить синтаксис
определения классов похож на Java. Microsoft сделала стандарт С#
открытым для широкого использования. Компилятор С# для платформы .NET
будет доступен в следующей версии Visual Studio. Похоже, что С#
станет идеальным языком создания приложений для новой
платформы.
© 2001 Корпорация
Microsoft. Все права защищены. Правила
использования | Политика
защиты | Кодекс
поведения
|
|