clr что это такое
Общеязыковая исполняющая среда CLR
1. Компиляция исходного кода в Microsoft Intermediate Language (IL)
2. Компиляция IL в специфичный для платформы код с помощью CLR
Основной механизм CLR физически имеет вид библиотеки под названием mscoree.dll (и также называется общим механизмом выполнения исполняемого кода объектов — Common Object Runtime Execution Engine). При добавлении ссылки на сборку для ее использования загрузка библиотеки mscoree.dll осуществляется автоматически и затем, в свою очередь, приводит к загрузке требуемой сборки в память. Механизм исполняющей среды отвечает за выполнение целого ряда задач. Сначала, что наиболее важно, он отвечает за определение места расположения сборки и обнаружение запрашиваемого типа в двоичном файле за счет считывания содержащихся там метаданных. Затем он размещает тип в памяти, преобразует CIL-код в соответствующие платформе инструкции, производит любые необходимые проверки на предмет безопасности и после этого, наконец, непосредственно выполняет сам запрашиваемый программный код.
Использование байт-кода с четко определенным универсальным синтаксисом дает ряд существенных преимуществ:
Независимость от платформы
Повышение производительности
Хотя язык 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?
CLR (Common language runtime) — общеязыковая исполняющая среда. Она обеспечивает интеграцию языков и позволяет объектам благодаря стандартному набору типов и метаданным), созданным на одном языке, быть «равноправными гражданами» кода, написанного на другом.
Другими словами CLR этот тот самый механизм, который позволяет программе выполняться в нужном нам порядке, вызывая функции, управляя данными. И все это для разных языков (c#, VisualBasic, Fortran). Да, CLR действительно управляет процессом выполнения команд (машинного кода, если хотите) и решает, какой кусок кода (функцию) от куда взять и куда подставить прямо в момент работы программы. Процесс компиляции представлен на рисунке:
Компилятор, помимо ассемблера IL создает полные метаданные.
Метаданные — набор из таблиц данных, описывающих то, что определено в модуле. Также есть таблицы, указывающие на что ссылается управляемый модуль (например, импортируемые типы и числа). Они расширяют возможности таких технологий как библиотеки типов и файлы языка описания интерфейсов (IDL). Метаданные всегда связаны с файлом с IL кодом, фактически они встроены в *.exe или *.dll.
Таким образом метаданные это таблицы, в которых есть поля, говорящие о том, что такой-то метод находится в таком-то файле и принадлежит такому-то типу(классу).
Вот как выглядят метаданные для моего примера (таблицы метаданных просто преобразованы в понятный вид с помощью дизассемблера ILdasm.exe. На самом деле это часть *.exe файла программы:
Разобравшись с основными понятиями, давайте посмотрим из чего же состоит тот самый управляемый модуль (или просто наш файл ConsoleApplication_Test_Csharp.exe, который выполняет вывод на экран возраста объекта):
Заголовок показывает на каком типе процессора будет выполняться программа. РЕ32 (для 32 и 64 битных ОС) или РЕ32+ (только для 64 битных ОС)
Заголовок CLR — содержит информацию, превращающую этот модуль в управляемый (флаги, версия CLR, точки входа в Main())
Метаданные — 2 вида таблиц метаданных:
1) определенные в исходном коде типы и члены
2) типы и члены, имеющие ссылки в исходном коде.
Код IL — Код, создаваемый компилятором при компиляции кода на C#. Затем IL преобразуется в процессорные команды (0001 0011 1101… ) при помощи CLR (а точнее JIT)
Работа JIT
И так, что же происходит, когда запускается впервые программа?
Сперва происходит анализ заголовка, чтобы узнать какой процесс запустить (32 или 64 разрядный). Затем загружается выбранная версия файла MSCorEE.dll ( C:\Windows\System32\MSCorEE.dll для 32разрядных процессоров)
После чего вызывается метод, расположенный MSCorEE.dll, который и инициализирует CLR, сборки и точку входа функции Main() нашей программы.
Для выполнения какого-либо метода, например System.Console.WriteLine(«Hello „), IL должен быть преобразован в машинные команды (те самые нули и единицы) Этим занимается Jiter или just-in-time compiler.
Сперва, перед выполнением Main() среда CLR находит все объявленные типы (например тип Console).
Затем определяет методы, объединяя их в записи внутри единой “структуры» (по одному методу определенному в типе Console).
Записи содержат адреса, по которым можно найти реализации методов (т.е. те преобразования, которые выполняет метод).
При первом обращение к функции 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 (пустая команда). Для этого при компиляции нужно добавить параметры
Чем же отличается управляемый код от неуправляемого?
Неуправляемый код компилируется для конкретного процессора и при вызове просто исполняется.
В управляемой среде компиляция производится в 2 этапа:
1) компилятор переводит C# код в IL
2) для исполнения нужно перевести IL код в машинный код процессора, что требует доп. динамической памяти и времени (как раз та самая работа JIT).
Взаимодействие с неуправляемым кодом:
— управляемый код может вызывать направляемую функцию из DLL посредствам P/Invoke (например CreateSemaphore из Kernel32.dll).
— управляемый код может использовать существующий COM-компонент (сервер).
— неуправляемый код может использовать управляемый тип (сервер). Можно реализовать COM — компоненты в управляемой среде и тогда не нужно вести подсчет ссылок интерфейсов.
Параметр /clr позволяет скомпилировать Visual С++ код в управляемые IL методы (кроме когда, содержащего команды с ассемблерными вставками ( __asm ), переменное число аргументов или встроенные процедуры ( __enable, _RetrurAddress )). Если этого сделать не получится, то код скомпилируется в стандартные х86 команды. Данные в случае IL кода не являются управляемыми (метаданные не создаются) и не отслеживаются сборщиком мусора (это касается С++ кода).
Система типов
В дополнение хочу рассказать о системе типов CTS, принятой Microsoft.
CTS (Common Type System) — общая система типов в CLR (тип, по-видимому — это аналог класса C#). Это — стандарт, признанный ECMA который описывает определение типов и их поведение. Также определяет правила наследования, виртуальных методов, времени жизни объектов. После регистрации ECMA стандарт получил название CLI ( Common Language Infrastructure)
— CTS поддерживает только единичное наследование (в отличие от С++)
— Все типы наследуются от System.Object (Object — имя типа, корень все остальных типов, System — пространство имен)
По спецификации CTS любой тип содержит 0 или более членов.
Поле — переменная, часть состояния объекта. Идентифицируются по имени и типу.
Метод — функция, выполняющая действие над объектом. Имеет имя, сигнатуру(число параметров, последовательность, типы параметров, возвр. значение функции) и модификаторы.
Свойство — в реализации выглядит как метод (get/set) а для вызывающей стороны как поле ( = ). Свойства позволяют типу, в котором они реализованы, проверить входные параметры и состояние объекта.
Событие — обеспечивает механизм взаимного уведомления объектов.
Public — метод доступен любому коду из любой сборки
Private — методы вызывается только внутри типа
Family (protected) — метод вызывается производными типами независимо от сборки
Assembly (internal) — метод вызывается любым кодом из той же сборки
Family or Assembly
(protected internal) — метод вызывается производными типами из любой сборки и + любыми типами из той же сборки.
CLS (Common Language Specification) — спецификации выпущенная Майкрософт. Она описывает минимальный набор возможностей, которые должны реализовать производители компиляторов, чтобы их продукты работали в CLR. CLR/CTS поддерживает больше возможностей, определенных CLS. Ассемблер IL поддерживает полный набор функций CLR/CTS. Языки (C#, Visual Basic) поддерживает часть возможностей CLR/CTS (в т.ч. минимум от CLS).
Пример на рисунке
Пример проверки на соответствие CLS
Атрибут [assembly: CLSCompliant(true)] заставляет компилятор обнаруживать любые доступные извне типы, содержащие конструкции, недопустимые в других языках.
Первое предупреждение: UInt32 Abc() возвращает целочисленное целое без знака. Visaul Basic, например, не работает с такими значениями.
Второе предупрждение: два открытых метода Abc() и abc() — одиноквые и отличаются лишь регистром букв и возвращаемым типом. VisualBasic не может вызывать оба метода.
Убрав public и оставив только sealed class SomeLibraryType оба предупреждения исчезнут. Так как SomeLibraryType по-умолчанию будет internal и не будет виден извне сборки.
Накалу страстей такой беседы позавидовали бы религиозные фанатики. Единственное, что спасает противников от крестовых походов друг на друга, вооружившись вилами и LangSpec’ами — то, что они разделены интернетом.
Так жить нельзя, господа. Мне захотелось исправить эту ситуацию, и выступить с одной из сторон. Этим постом я попробую нанести сообществу непоправимую пользу и разобраться с мифами, на обсуждение которых, а не на взаимное членовредительство, к сожалению, и уходят силы спорщиков. А так как я в своё время перелез с C++ на C# и всё вокруг него, то я буду развенчивать негативные мифы, прибавлять позитива и всячески приукрашивать действительность — а как без этого. И — заметьте — это обойдется совершенно бесплатно для M$. Ну а сделать я это хочу в формате Q&A.
#. C# и CLR — это такая VM, т.е. интерпретатор, а, значит, очень медленно и печально. Мне нужно, чтобы было быстро, очень быстро!
Я не буду рассказывать тут, чем компиляция отличается от интерпретации. Просто хочу заметить вот что: джентльмены, недавний опрос на Хабрахабре показал — большинство разработчиков так или иначе используют “управляемые” языки, которые компилируются не в нативный код, а в байт-коды, исполняемые интерпретаторами — непосредственными или компилирующего типа. Всякие TraceMonkey, LuaJIT, YARV как раз примеры для последней классификации. Это означает, что переход на другую платформу сходной архитектуры заведомо не сделает приложение медленнее. В этом смысле беспокоиться не о чем.
Однако, CLR — это sort of virtual machine, но это не интерпретатор. Еще раз повторюсь: MS.NET это НЕ ИНТЕПРЕТАТОР БАЙТКОДА. Специальный компилятор JIT постепенно преобразует байткод программы в нативный код, примерно такой же, который выдаёт компилятор C++. Текущая реализация CLR — MS.NET и Mono гарантируют, что ЛЮБОЙ код, который будет исполняться, преобразуется в нативный код. При этом для десктопов утверждение еще сильнее: любой код будет откомпилирован только один раз. Причём то, что он компилируется “на лету”, теоретически позволяет более оптимально использовать особенности конкретного процессора, а значит, сильнее соптимизировать код.
Более того, сравнение абсолютных цифр на бенчмарках показывает, что CLR оказывается на порядки эффективнее, чем популярные скриптовые языки типа JavaScript и Ruby, тоже использующие технологию JIT.
#. Языки со сборкой мусора отстают от языков типа C++ по скорости.
Верно, тут вы весьма близки к истине. Но, как и любой холиварщик, немного не договариваете. Правильно фраза будет звучать так: “корректно написанное и целиком вручную оптимизированное нативное приложение без ошибок, использующее специальные методики управления памятью, будет быстрее, чем приложение с автоматической сборкой мусора”.
Но для более-менее серьезного ПО создать такое приложение означает огромное количество затраченных усилий. Значительно превышающее то, которое потребуется для управляемого языка.
Именно поэтому появились языки высокого уровня — в длительной перспективе в среднем код, выдаваемый компилятором, будет содержать меньше ошибок и работать быстрее, чем написанный вручную.
И — да — тупые цифры не лгут: выделение памяти в языках со сборкой мусора выполняется БЫСТРЕЕ, и _не_ фрагментирует кучу, в отличие от с++. Обработка исключений в управляемых языках тоже выполняется быстрее.
А тут еще в дело вступает фактор времени, и стоимости разработки, включая количество ошибок. Потому что ошибка повреждения или утекшей памяти… хм… когда же я её видел в CLR последний раз? Лет 10 назад, не меньше.
#. Программы на CLR жрут очень много памяти. Прям вааще всё жрут, ничего не оставляют…
Хм. Сравнимое нагруженное Ruby-on-Rails-приложение на сервере кушает 100-150МБ RAM, примерно столько же, сколько и ASP.NET CLR сайт. Тут нет большой разницы.
Конечно, в небольших скриптовых задачах тот же Ruby оказывается гораздо эффективнее. Но вопрос не о скриптовых задачах — на проектах из реальной жизни, которые приносят деньги, аппетиты CLR выглядят соразмерными другим технологиям, и я не могу согласиться с определением “жрут очень много”.
#. Ну ладно, ладно, GC это хорошо. Но сборщик мусора — очень капризное животное, там есть огромное количество настроек. Их же никто не может корректно выставить — ручное вмешательство только вредит. GC в моём ZZZ работает и так! Сам!
Между прочим, CLR обладает одним из лучших сборщиков мусора на сегодняшний день. Первый его вариант был написан на LISPe, чтобы явственнее выразить семантику отношений между объектами в памяти и выполнить автоматический анализ корректности алгоритма, а затем переписан на С++. С тех пор прошло много времени, GC был обкатан миллионами разработчиков и не меньшим количеством проектов. Не течёт, что ни делай!
В качестве настроек выступает один ключ в файле конфигурации gcServer=”true/false”. Включает параллельную сборку мусора, а так же другие оптимизации. По умолчанию стоит в false, чтобы не мешать интерактивному режиму UI (работа gc незаметна для UI) на однопроцессорных машинах. В CLR 4.0 появились новые настройки, но суть та же — отлично работает “из коробки”, убирайте свои пассатижи подальше.
#. А в моём любимом языке ZZZ есть FFI, и поэтому я могу писать к нему расширения на С, если мне нужна скорость. Ни разу, правда, не писал, ну и что! Ведь могу же! А что в CLR/C#, надо всё переписывать на управляемый язык?
Очень рад за ZZZ. Вы удивитесь, но в CLR тоже присутствует возможность вызывать функции из нативных dll, написанных на старом добром С. И, конечно, передавать туда данные и получать обратно. Причем, в отличие от большинства FFI, вам не нужно проектировать dll под FFI — использовать соглашения по вызову и специальные типы данных. CLR всеяден, его можно гибко настроить на поедание почти любой библиотеки. Отдельным образом включена и автоматизирована поддержка COM, для более удобного доступа к возможностям Windows.
Это называется Interop/Platform Invoke
#. Писать для CLR можно только из Visual Studio. И только под Windows. И то, и то опять стоит денег.
Неправда. Есть SharpDevelop, который достаточно хорош для бесплатной среды; есть MonoDevelop, который тоже хорош, и работает как по Win, так и в *nix. Есть плагины к Eclipse; кстати, при помощи IKVM.NET для запуска Eclipse не нужна Java, хватает одного CLR.
Облегченная версия Visual Studio Express позволяет создавать полноценные приложения в Win. Бесплатного MS SQL Express хватит надолго для большинства проектов.
#. Место CLR — на сервере. А Mono — страшная неюзабельная ненадежная гадость, не выросшая из пеленок MiguelDeIcaza’s Labs ©.
Точно. На сервере приложений и на веб-сервере — в CLR есть свои Rails (ASP.NET MVC), есть свой Hibernate и десятки других ORM. Подойдёт для всего. Ну это разве страшно — мы все постепенно переползаем в веб.
Кстати, а вы слышали, что приложения Mono компилируется и для iPhone и iPad (#MonoTouch)? Да и тот же Unity3D это умеет.
#. Использование CLR заставляет меня переходить на C#, я не хочу его учить!
И совершенно не нужно. Да, в C# наиболее полно доступны все возможности CLR, но никто не заставляет пользоваться именно им. CLR — это не только C#, это отличная платформа и BCL, предоставляющая качественную объектную модель и инструменты. Существует огромное количество языков — новых, таких, как Boo, Nemerle, F#, или ранее известных: Delphi, Ada, Lisp, VB, php, в качестве back-end использующих CLR.
С этой точки зрения CLR похожа на LLVM — предоставляет сервисы нижнего уровня, такие, как IL (байт-код) и JIT, сборка мусора, объектная модель, общая система типов, стандартная библиотека, система безопасности и т.д.
#. С# это быдлоязык для ыnterprise, он застрял в прошлом веке, а в моём языке ZZZ каждые полгода новые фишечки!
Да, C# сейчас плотно обосновался в low-cost секторе enterprise — всё благодаря его характеристикам: на нем достаточно просто писать, статическая типизация и управляемая среда позволяет исключить целый класс ошибок, присущих скриптовым языками или языкам более низкого уровня, IDE предоставляет доступ ко всем нужным инструментам в пару кликов, встроенная прямо в IDE документация и первоклассный IntelliSense.
Благодаря этому решения на C#/CLR обходятся не так дорого, как в Java.
В C# соблюдается принцип обратной совместимости, но это не мешает добавлять новые features в язык. Уже сейчас есть параметрический полиморфизм (это когда Vector), лямбда-функции и замыкания, впервые из всех языков появились LINQ (Language-integrated queries) на базе ограниченного цитирования, присутствует вывод типов, появился целый пласт DLR. В 5.0 версии появляется встроенная поддержка асинхронного программирования.
CLR/С# не так плох, как вы думаете, и это ничего не стоит проверить. Но если вам мало C#, есть F# (порт Caml) и Nemerle (гибрид C# и функционального языка), есть даже CLR C++ — берите из двух миров то, что вам надо, и совмещайте.
#. Так, алоэ, я кое-что вспомнил. О какой кросcплатформенности речь, когда чтобы запустить под Mono, мне надо всё перекомпилировать. Это же как в старом добром С, чем лучше-то?!
Очередная глупость. Я не знаю, кто вам сказал, но в целом полностью управляемое CLR-приложение, скомпилированное под Windows, НЕ НУЖНО ПЕРЕКОМПИЛИРОВАТЬ. Можно ПРОСТО перенести на Linux с установленным Mono, скомандовать mono myapp.exe, и оно запустится. И наоборот тоже работает. Я проверял.
Правда, здесь вступает в ход связывание с библиотеками. Это как gems в Ruby — если этот конкретный gem использует нативные библиотеки, то вам нужно установить эти самые нативные библиотеки. Но а вообще — полно чисто Ruby-гемов.
No magic, как-то так.
Если же вы хотите использовать общую управляемую библиотеку, то специальный механизм, называемый GAC (Global Assembly Cache), используя механизмы криптографии, позаботится об отсутствии дублирования, о том, что нужная вам библиотека — именно та и именно той версии, которую вы ждёте.
#. А вот мои знакомые программисты… Они говорили, что в комплект разработчика на Visual Studio IDE и C# входит обязательный ректальный виброзонд и инструкция по его непрерывному ношению!
OMFG O_o! Я абсолютно ответственно заявляю: ваших знакомых программистов обманули. Я бы порекомендовал вам пойти и помочь им отказаться от ношения самозваного зонда, но, боюсь, что они уже вошли во вкус и не смогут… Но ведь MS и CLR тут не при чём, так?
Выводы
Конечно, мне можно возразить. Буду рад, если кто-то захочет поправить меня или дополнить, а может быть, и опровергнуть.
В общем и целом, я рассказал, как обстоит дело, чем, надеюсь, причинил немало добра своим коллегам по цеху CLR. Надеюсь, теперь не будет дурацких вопросов, типа “зачем C#, если есть Python, а при нём GC”.
Обзор среды CLR
.NET предоставляет среду выполнения (среду CLR), которая выполняет код и предлагает службы, облегчающие процесс разработки.
Компиляторы и иные средства позволяют использовать функции среды CLR и дают разработчикам возможность писать код, использующий преимущества этой среды управляемого выполнения. Код, разработанный с использованием языкового компилятора для среды выполнения, называют управляемым. В нем используются преимущества таких средств, как объединение языков программирования, объединенная обработка исключений, усиленная безопасность, поддержка отслеживания версий и развертывания, упрощенная модель взаимодействия компонентов, а также службы отладки и профилирования.
Компиляторы и средства могут создавать выходные данные для общеязыковой среды выполнения (CLR), поскольку система типов, формат метаданных и среда выполнения (виртуальная система выполнения) определяются открытым стандартом — спецификацией общеязыковой инфраструктуры ECMA. Дополнительные сведения см. в разделе Спецификации ECMA для C# и инфраструктуры Common Language Infrastructure (CLI).
Чтобы включить в среде выполнения предоставление служб управляемому коду, языковые компиляторы должны предоставлять метаданные с описанием типов, членов и ссылок в коде. Метаданные хранятся вместе с кодом. Они содержатся в каждом загружаемом переносимом исполняемом (PE) файле среды CLR. Метаданные в среде выполнения используются для поиска и загрузки классов, размещения экземпляров в памяти, разрешения имен при вызове методов, создания машинного кода, обеспечения безопасности и установки границ контекста времени выполнения.
Среда CLR упрощает разработку компонентов и приложений, объекты которых могут работать в разных языках. Объекты, написанные на разных языках, могут взаимодействовать друг с другом, а их поведение может быть тесно интегрировано. Например, разработчик может определить класс, а затем на другом языке создать производный от него класс или вызвать метод из исходного класса. Можно также передать экземпляр класса в метод класса, написанного на другом языке. Такая интеграция языков программирования возможна в силу того, что языковые компиляторы и программы, которые обращаются к среде выполнения, используют систему общих типов, определенную средой выполнения, и следуют правилам среды выполнения при определении новых типов, а также при создании, использовании, сохранении и привязки к типам.
В составе своих метаданных все управляемые компоненты содержат сведения о компонентах и ресурсах, на базе которых они построены. Среда выполнения использует эти сведения, чтобы обеспечить наличие всех необходимых ресурсов для компонента или приложения. Это снижает вероятность сбоев кода из-за каких-либо неудовлетворенных зависимостей. Сведения о регистрации и данные о состоянии больше не сохраняются в реестре, где их трудно задавать и поддерживать. Вместо этого сведения об определяемых разработчиком типах (и их зависимостях) сохраняются вместе с кодом в виде метаданных, что существенно упрощает репликацию и удаление компонентов.
Языковые компиляторы и программы предоставляют функции среды выполнения так, чтобы они были полезны и интуитивно понятны для разработчиков. Это означает, что некоторые средства среды выполнения могут быть заметными в одной среде больше, чем в другой. Характеристики среды выполнения зависят от используемых языковых компиляторов и программ. Например, разработчик Visual Basic при работе со средой CLR может заметить, что язык Visual Basic имеет больше средств объектно-ориентированного программирования, чем раньше. Среда выполнения предоставляет следующие преимущества:
возможность легко использовать компоненты, разработанные на других языках;
расширяемые типы, предоставляемые библиотекой классов;
языковые возможности (например, наследование, интерфейсы и перегрузку) для объектно-ориентированного программирования;
поддержку явной свободной потоковой обработки, позволяющую создавать масштабируемые многопотоковые приложения;
поддержку структурированной обработки исключений;
поддержку настраиваемых атрибутов;
использование делегатов вместо указателей на функции для повышения типобезопасности и уровня защиты. Подробнее о делегатах см. в разделе Система общих типов CTS.