Что такое cts clr cls

Что такое управляемый код

Сравните это с запуском программы C/C++, которая также называется «неуправляемым кодом». В мире неуправляемого кода практически за все отвечает программист. Сама программа представляет собой двоичный файл, который операционная система (ОС) загружает в память и запускает. За все остальное — от управления памятью до различных аспектов безопасности — отвечает программист.

Промежуточный язык и выполнение

После создания IL из кода высокого уровня вы, скорее всего, захотите запустить его. В этот момент среда CLR берет управление на себя и запускает процесс JIT-компиляции, используя JIT для преобразования кода из промежуточного языка в машинный код, который может выполняться на ЦП. Таким образом, среде CLR точно известно, что делает код, поэтому она может эффективно управлять им.

Промежуточный язык иногда называют языком CIL или MSIL.

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

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

Аналогично, C# — это язык, позволяющий использовать неуправляемые конструкции, такие как указатели, прямо в коде с помощью так называемого небезопасного контекста, указывающего часть кода, для которой выполнение не управляется средой CLR.

Источник

Система общих типов CTS

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

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

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

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

Предоставляет библиотеку, которая содержит типы-примитивы (например, Boolean, Byte, Char, Int32 и UInt64), используемые в разработке приложений.

Типы значений — это типы данных, объекты которых представлены фактическим значением объекта. Если экземпляр типа значения присваивается переменной, то эта переменная получает новую копию значения.

Ссылочные типы — это типы данных, объекты которых представлены ссылкой (аналогичной указателю) на фактическое значение объекта. Если экземпляр ссылочного типа присваивается переменной, то эта переменная будет ссылаться (указывать) на исходное значение. Копирования при этом не происходит.

Классы

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

ХарактеристикаОписание
sealedУказывает, что наследование от данного класса не допускается.
реализуетПоказывает, что в классе используется один или несколько интерфейсов за счет предоставления реализаций их членов.
abstractУказывает, что создавать экземпляры этого класса нельзя. Чтобы его использовать, необходимо создать из данного класса производный класс.
наследуетПоказывает, что экземпляры класса можно использовать везде, где задан базовый класс. Производный класс, который наследует от базового, может использовать реализацию любых открытых членов, предоставляемых базовым классом, либо переопределить реализацию этих открытых членов собственной их реализацией.
exported или not exportedПоказывает, виден ли класс за пределами сборки, в которой он определен. Эта характеристика применима только к классам верхнего уровня, но не к вложенным классам.

Класс может также быть вложен в родительский класс или родительскую структуру. Вложенные классы также имеют характеристики членов. Дополнительные сведения см. в разделе Вложенные типы.

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

Класс может реализовывать любое число интерфейсов, однако он может наследовать только от одного базового класса в дополнение к System.Object, от которого неявно наследуют все классы. Любой класс должен иметь по крайней мере один конструктор, который инициализирует новые экземпляры класса. Если конструктор не определен явно, большинство компиляторов автоматически предоставят заданный конструктор без параметров.

Структуры

Как и в классах, в структурах определяются и данные (поля структуры), и операции, которые можно выполнять над этими данными (методы структуры). Это означает, что применительно к структурам можно вызывать методы, в том числе виртуальные методы, определенные в классах System.Object и System.ValueType, а также любые методы, определенные в самом типе значения. Другими словами, структуры могут иметь поля, свойства и события, а также статические и нестатические методы. Можно создавать экземпляры структур, передавать их в качестве параметров, хранить их в качестве локальных переменных либо в поле другого типа значения или ссылочного типа. Структуры также могут реализовывать интерфейсы.

Кроме того, типы значений отличаются от классов в ряде других вопросов. Во-первых, хотя они неявно наследуют от System.ValueType, они не могут напрямую наследовать ни от какого типа. Аналогичным образом, все типы значений являются запечатанными. Это значит, что наследование от них не допускается. Им также не требуются конструкторы.

Для каждого типа значения среда CLR предоставляет соответствующий упакованный тип — класс, имеющий то же состояние и поведение, что и тип значения. Экземпляр типа значения упаковывается при передаче в метод, принимающий параметр типа System.Object. Распаковка (преобразование из экземпляра класса обратно в экземпляр типа значения) производится при возврате управления после вызова метода, принимающего тип значения в качестве параметра по ссылке. В некоторых языках необходимо применение специального синтаксиса, когда требуется упакованный тип; в других упакованный тип используется автоматически, когда он нужен. При определении типа значений определяется и упакованный, и неупакованный тип.

Перечисления

Перечисление — это тип значения, который напрямую наследует от System.Enum и предоставляет альтернативные имена для значений базового типа-примитива. Тип перечисления имеет имя, базовый тип, который должен быть одним из встроенных целочисленных знаковых или беззнаковых типов (например, Byte, Int32 или UInt64), а также набор полей. Поля являются статическими полями литералов, каждое из которых представляет константу. Одно значение можно присвоить нескольким полям. В этом случае необходимо пометить одно из значений как первичное значение перечисления для отражения и преобразования строк.

Значение базового типа можно присвоить перечислению и наоборот (среда выполнения не требует приведения типов). Можно создавать экземпляры перечислений и вызвать методы System.Enum, а также любые методы, определенные в базовом типе перечисления. При этом в некоторых языках передача перечисления в виде параметра может не допускаться, если требуется передать экземпляр базового типа (или наоборот).

К перечислениям применяются следующие дополнительные ограничения.

В них нельзя определять собственные методы.

В них нельзя реализовывать интерфейсы.

В них нельзя определять свойства и события.

Они не могут быть универсальными, если только они становятся таковыми за счет вложения внутрь универсального типа. То есть перечисления не могут иметь свои собственные параметры типов.

Вложенные типы (в том числе перечисления), созданные в Visual Basic, C# и C++, содержат параметры всех включающих их универсальных типов и, таким образом, являются универсальными, даже если они не имеют своих собственных параметров типов. Дополнительные сведения см. в подразделе «Вложенные типы» раздела справки Type.MakeGenericType.

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

Интерфейсы

Интерфейс задает контракт, определяющий отношение типа «может» или «имеет». Интерфейсы часто используются для реализации различных функций, например для сравнения и сортировки (интерфейсы IComparable и IComparable ), проверки равенства (интерфейс IEquatable ) или перечисления элементов коллекции (интерфейсы IEnumerable и IEnumerable ). Интерфейсы могут иметь свойства, методы и события, являющиеся абстрактными членами. Это значит, что хотя в интерфейсе определяются члены и их сигнатуры, за определение функциональности всех членов интерфейса отвечает тип, реализующий данный интерфейс. Любой класс или структура, реализующие интерфейс, должны содержать определения абстрактных членов, объявленных в этом интерфейсе. Обязательным условием реализации интерфейса в классе или структуре также может быть реализация одного или нескольких других интерфейсов.

К интерфейсам применяются следующие ограничения.

Интерфейс может быть объявлен с любой доступностью, однако, члены интерфейса всегда должны иметь доступность уровня public.

В интерфейсах нельзя определять конструкторы.

В интерфейсах нельзя определять поля.

В интерфейсах можно определять только члены экземпляров. Статические члены определять в них нельзя.

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

Делегаты

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

Аналогичным образом, тип возвращаемого значения делегата совместим с типом возвращаемого значения метода, если тип возвращаемого значения метода является более строгим, чем тип возвращаемого значения делегата, так как это гарантирует, что возвращаемое значение метода может быть безопасно приведено к типу возвращаемого значения делегата.

Например, делегат с параметром типа IEnumerable и типом возвращаемого значения Object может представлять метод с параметром типа Object и типом возвращаемого значения IEnumerable. Дополнительные сведения и примеры с кодом см. в разделе Delegate.CreateDelegate(Type, Object, MethodInfo).

Делегат называют связанным с методом, который он представляет. Помимо привязки к методу, делегат может быть связан с отдельным объектом. Этот объект представляет первый параметр метода и передается методу при каждом вызове делегата. Если это метод экземпляра, то связанный объект передается как неявный параметр this ( Me в Visual Basic); если метод является статическим, то объект передается как первый формальный параметр метода, и сигнатура делегата при этом должна соответствовать остальным параметрам. Дополнительные сведения и примеры с кодом см. в разделе System.Delegate.

Все делегаты наследуются от System.MulticastDelegate, который наследуется от System.Delegate. Языки C#, Visual Basic и C++ не допускают наследование от этих типов. Вместо этого они предоставляют ключевые слова для объявления делегатов.

Поскольку делегаты наследуются от MulticastDelegate, делегат имеет список вызова, представляющий собой список методов, которые представляет делегат и которые выполняются при вызове делегата. Все методы в списке получают аргументы, предоставляемые при вызове делегата.

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

Зачастую, как, например, в случае с методами обратного вызова, делегат представляет только один метод, поэтому единственное действие, которое нужно выполнить, — это создание и вызов делегата.

Применение этих методов к делегатам обработчиков событий в C#, C++ и Visual Basic необязательно, так как эти языки предоставляют синтаксис для добавления и удаления обработчиков событий.

Определения типов

Определение типа включает следующее:

все определенные в типе атрибуты;

доступность (видимость) типа;

базовый тип данного типа;

все интерфейсы, реализованные этим типом;

определения каждого члена типа.

Атрибуты

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

Сами атрибуты представляют собой классы, производные от System.Attribute. Любой язык, поддерживающий использование атрибутов, имеет собственный синтаксис для применения атрибутов к элементам языка. Атрибуты можно применять почти к любым элементам языка; конкретные элементы, к которым можно применять определенный атрибут, задаются атрибутом AttributeUsageAttribute, примененным к классу этого атрибута.

Доступность типов

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

Специальные возможностиОписание
publicТип доступен во всех сборках.
сборкаТип доступен только в пределах своей сборки.

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

Имена типов

Система общих типов накладывает на имена только два следующих ограничения.

Все имена кодируются в виде строк, состоящих из символов Юникода (16-разрядная кодировка).

Имена не могут иметь внедренное (16-разрядное) значение 0x0000.

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

Базовые типы и интерфейсы

Тип может наследовать значения и поведение другого типа. Система общих типов не разрешает наследование от нескольких базовых типов.

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

Члены типов

Среда выполнения позволяет определять члены типа, задающих поведение и состояние типа. К членам типа относятся:

Константы, значение которых задается во время разработки. Они являются статическими членами класса, хотя и не определяются с помощью ключевого слова static ( Shared в Visual Basic).

Доступные только для чтения переменные, значения которых задаются в конструкторе класса.

В следующем примере демонстрируются эти два способа использования доступных только для чтения полей.

Свойства

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

MSIL-код типа, который содержит свойство, доступное для чтения, наряду с самим свойством включает метод get_ имя_свойства. MSIL-код типа, который содержит свойство, доступное для чтения, наряду с самим свойством включает метод set_ имя_свойства.

Методы

Метод описывает операции, доступные в определенном типе. Сигнатура метода указывает допустимые типы всех его параметров и возвращаемого значения.

Хотя большинство методов определяют точное число параметров, необходимых для вызовов метода, некоторые методы поддерживают переменное число параметров. Конечный объявленный параметр этих методов помечается атрибутом ParamArrayAttribute. Компиляторы языка обычно предоставляют ключевое слово, такое как params в C# и ParamArray в Visual Basic, которое исключает необходимость явного использования ParamArrayAttribute.

Конструкторы

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

Если исходный код класса не содержит явного определения конструктора, то компилятор включает заданный конструктор без параметров. Однако если исходный код класса определяет только параметризованные конструкторы, компиляторы Visual Basic и C# не создают конструктор без параметров.

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

События

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

Вложенные типы

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

Особенности вложенных типов не всегда понятны некоторым разработчикам; эти типы не должны быть открыто видимыми, если существенной причины для подобной видимости не имеется. В хорошо спроектированной библиотеке разработчикам редко приходится использовать вложенные типы для создания экземпляров объектов или объявления переменных.

Характеристики членов типов

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

ХарактеристикаПрименениеОписание
abstractМетоды, свойства и событияТип не предоставляет реализацию метода. Типы, которые наследуют или реализуют абстрактный метод, должны предоставлять реализацию метода. Единственное исключение — когда производный тип является абстрактным. Все абстрактные методы являются виртуальными.
private, family, assembly, family and assembly, family or assembly, publicВсеОпределяют доступность члена.

private
Доступен только изнутри типа, к которому принадлежит член, или изнутри вложенного типа.

family
Доступен изнутри типа, к которому принадлежит член, а также из производных от него типов.

сборка
Доступен только в сборке, в которой определен тип.

family and assembly
Доступен только в типах с уровнем доступа family и assembly.

family or assembly
Доступен только в типах с уровнем доступа либо family, либо assembly.

public
Доступен в любом типе.

finalМетоды, свойства и событияВиртуальный метод нельзя переопределить в производном типе.
initialize-onlyПоляЗначение можно только инициализировать и невозможно установить после инициализации.
экземплярПоля, методы, свойства и событияЕсли член не помечен как static (C# и C++), Shared (Visual Basic), virtual (C# и C++) или Overridable (Visual Basic), то он является членом экземпляра (ключевое слово instance не используется). Копий таких членов в памяти будет столько, сколько объектов их использует.
литералПоляЗначение, присвоенное полю, является фиксированным значением встроенного типа значения и становится известным во время компиляции. Поля литералов иногда называются константами.
newslot или overrideВсеОпределяет способ взаимодействия члена с унаследованными членами, имеющими ту же сигнатуру:

newslot
Скрывает унаследованные члены с той же сигнатурой.

переопределенный
Заменяет определение наследуемого виртуального метода.

По умолчанию используется характеристика newslot.

статическийПоля, методы, свойства и событияЧлен принадлежит к типу, в котором он определен, а не к конкретному экземпляру типа. Член существует, даже если экземпляр типа не создан, и является общим для всех экземпляров типа.
виртуальныйМетоды, свойства и событияМетод может реализовываться с помощью производного типа и вызываться либо статически, либо динамически. Если используется динамический вызов, то вызываемая реализация метода определяется типом экземпляра, выполняющего вызов во время выполнения, а не типом, известным во время компиляции. Для статического вызова виртуального метода может потребоваться приведение переменной к типу, который использует нужную версию метода.

Перегрузка

У каждого члена типа есть уникальная сигнатура. Сигнатуры методов содержат имя метода и список параметров (порядок и типы аргументов метода). В типе можно определить несколько методов с одним именем и разными сигнатурами. При этом метод будет называться перегруженным. Например, в System.Char метод IsDigit перегружен. Один метод принимает параметр Char. Другой метод принимает String и Int32.

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

Наследование, переопределение и скрытие членов

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

Источник

Что такое cts clr cls

Предыдущее состояние дел

Традиционно разработка программного обеспечения для операционных систем семейства Windows предполагает использование языка программирования C в сочетании с Windows API (Application Programming Interface – интерфейс программирования приложений). Несмотря на тот факт, что в рамках этого проверенного временем подхода было создано очень много вполне успешных приложений, мало кто станет оспаривать то, что процесс создания приложений непосредственно с помощью API оказывается очень трудоемким делом.

Первая очевидная проблема заключается в том, что C является очень лаконичным языком. Разработчики программ на языке C вынуждены «вручную» управлять памятью, использовать безобразную арифметику указателей и ужасные синтаксические конструкции. К тому же, поскольку C является структурным языком программирования, ему не хватает преимуществ, обеспечиваемых объектно-ориентированным подходом (здесь можно вспомнить о «макаронных» программах). Когда вы объединяете тысячи глобальных функций и типов данных, определенных в рамках Win32 API, с языком, который и без того выглядит устрашающе, не следует удивляться тому, что среди используемых сегодня программ оказывается так много ненадежных.

Огромным шагом вперед по сравнению с подходом, предполагающим использование C/API, явился переход к применению языка программирования C++. Во многих отношениях язык C++ можно рассматривать, как объектно-ориентированную надстройку над C. Поэтому, хотя при использовании C++ уже можно использовать преимущества известных «краеугольных камней ООП» (инкапсуляция, наследование и полиморфизм), этот подход оставляет программиста во власти многих болезненных аспектов языка C (управление памятью «вручную», безобразная арифметика указателей и ужасные синтаксические конструкции).

Несмотря на сложность, сегодня существует множество каркасов программирования на C++. Например, MFC (Microsoft Foundation Classes – библиотека базовых классов Microsoft) снабжает разработчика набором C++-классов, упрощающих создание Win32-приложений. Главной задачей MFC является представление «разумного подмножества» Win32 API в виде набора классов, «магических» макросов и средств автоматического генерирования программного кода (обычно называемых мастерами). Несмотря на очевидную пользу указанного каркаса приложений (как и многих других средств разработчика, использующих C++), программирование на C++ остается трудной задачей, и на этом пути нелегко полностью избежать ошибок ввиду «тяжелой наследственности», обусловленной связью с языком C.

Подход Visual Basic 6.0

Благодаря искреннему желанию насладиться более простой жизнью, многие программисты ушли от «мира каркасов» приложений на базе C(++) к более дружественным языкам, таким, как, например, Visual Basic 6.0 (VB6). Язык VB6 стал популярным благодаря тому, что он дает возможность строить сложные интерфейсы пользователя, библиотеки программного кода (например, COM-серверы) и системы доступа к данным, затрачивая минимум усилий. В сравнении с MFC, VB6 еще глубже скрывает от глаз разработчика сложность Win32 API, используя для этого целый ряд интегрированных мастеров, внутренних типов данных, классов и специфических для VB функций.

Было предложено использовать Java. Язык программирования Java является (почти) полностью объектно-ориентированным и имеет синтаксические корни в C++. Многие знают, что поддержка межплатформенной независимости – далеко не единственное преимущество Java. Java (как язык) избавлен от многих синтаксических несообразностей C++. Java (как платформа) предлагает программисту большое число встроенных «пакетов», содержащих различные определения типов. С помощью этих типов, используя «только Java», можно строить приложения, предлагающие сложный интерфейс пользователя, обеспечивающие связь с базами данных, обмен сообщениями или работу клиента в Web.

Хотя Java – очень элегантный язык, его потенциальной проблемой является то, что использование Java в цикле разработки обычно означает необходимость использования Java и для взаимодействия клиента с сервером. Как следствие, Java не позволяет возлагать большой надежды на возможности языковой интеграции, так как это идет вразрез с декларируемой целью Java (единый язык программирования для всех задач). Реальность, однако, такова, что в мире существуют миллионы строк программного кода, которым бы идеально подошло взаимодействие с более новым программным кодом. К сожалению, Java делает эту задачу проблематичной.

Java в чистом виде просто не подходит для многих приложений, интенсивно использующих графику или сложные вычисления (в этих случаях скорость работы Java оставляет желать лучшего). Для таких программ в соответствующем месте выгоднее использовать язык более низкого уровня (например, C++). Увы, пока Java не обеспечивает более широкие возможности доступа к «чужеродным» API, истинная интеграция различных языков оказывается практически невозможной.

Модель COM (Component Object Model – модель компонентных объектов) была предыдущим каркасом разработки приложений Microsoft. По сути, COM – это архитектура, «заявившая» следующее: если класс будет построен в соответствии с правилами COM, то получится блок двоичного кода многократного использования.

Прелесть двоичного COM-сервера в том, что способ доступа к нему не зависит от языка. Поэтому программисты, использующие C++, могут строить COM-классы, пригодные для использования в VB6. Программисты, применяющие Delphi, могут использовать COM-классы, построенные с помощью C, и т.д. Однако, и вы, возможно, об этом знаете, независимость COM от языка несколько ограничена. Например, нет возможности получить новый COM-класс из уже существующего (поскольку COM не предлагает поддержки классического наследования). Вместо этого для использования типов COM-класса вам придется указать несколько неуклюжее отношение «обладания».

Еще одним преимуществом COM является прозрачность дислокации. Используя такие конструкции, как идентификаторы приложения (AppID), «заглушки» и «заместители» в среде выполнения COM, программист может избежать необходимости непосредственного обращения к сокетам, RPC-вызовам и другими низкоуровневым элементам. Рассмотрим, например, следующий программный код VB6 COM-клиента.

‘ Этот блок программного кода VB6 может активизировать COM-класс,

‘ созданный на любом языке, поддерживающем COM, и размещенный

‘ в любой точке сети (включая вашу локальную машину).

Set с = New MyCOMClass ‘ Размещение выясняется с помощью AppID.

Хотя COM можно считать очень успешной объектной моделью, внутренне она чрезвычайно сложна (по крайней мере, пока вы не потратите несколько месяцев на изучение ее внутренних механизмов – особенно если вы программируете на C++). С целью упрощения процесса разработки бинарных COM-объектов было создано множество каркасов разработки приложений с поддержкой COM. Среди них, например, библиотека ATL (Active Template Library – библиотека активных шаблонов), которая обеспечивает еще одно множество C++-классов, шаблонов и макросов, упрощающих создание COM-типов.

Многие другие языки также в значительной степени скрывают инфраструктуру COM от глаз программиста. Однако поддержки самого языка оказывается недостаточно для того, чтобы скрыть всю сложность COM. Даже при использовании относительно простого совместимого с COM языка (например, VB6), вы все равно вынуждены бороться с «хрупкими» параметрами регистрации и многочисленными проблемами, связанными с инсталляцией приложений (в совокупности называемыми «кошмаром DLL»).

Подход Windows DNA

Ко всем указанным выше сложностям еще добавляется такая мелочь, как Интернет. За последние несколько лет Microsoft добавила в свое семейство операционных систем и других продуктов множество связанных с Интернет возможностей. К сожалению, создание Web-приложений в рамках совместимой с COM архитектуры Windows DNA (Distributed interNet Applications Architecture – архитектура распределенных сетевых приложений) также оказывается очень непростым делом.

Некоторая доля этой сложности вытекает из того простого факта, что Windows DNA требует использования множества технологий и языков (ASP, HTML, XML, JavaScript, VBScript, а также COM(+) и API доступа к данным, например ADO).

Одной из проблем является то, что с синтаксической точки зрения многие из этих технологий совершенно не связаны одна с другой. Например, в JavaScript используется синтаксис, во многом подобный C, a VBScript является подмножеством VB6. COM-серверы, созданные для работы в среде выполнения COM+, по виду сильно отличаются от ASP-страниц, которые их вызывают. Результат – чрезвычайно запутанная смесь технологий.

К тому же, и это, возможно, самое важное, каждый язык и каждая технология имеют свои собственные системы типов (которые могут быть совершенно не похожими одна на другую). Например, нельзя сказать, что «int» в JavaScript и «Integer» в VB6 означают в точности одно и то же.

Роль библиотек базовых классов

Например, библиотеки базовых классов определяют типы, упрощающие доступ к базам данных, работу с XML, поддержку программной безопасности и создание Web-приложений (а также обычных настольных и консольных приложений) клиента. Схема высокоуровневых взаимосвязей между CLR, CTS, CLS и библиотекой базовых классов показана на рис. 1.1.

Что такое cts clr cls. Смотреть фото Что такое cts clr cls. Смотреть картинку Что такое cts clr cls. Картинка про Что такое cts clr cls. Фото Что такое cts clr cls

Рис. 1.1. CLR, CTS, CLS и библиотека базовых классов

Многие синтаксические конструкции C# построены с учетом решений, принятых в Visual Basic 6.0 и C++. Например, как и в VB6, в C# поддерживаются формальные свойства типов (в противоположность традиционным методам get и set) и возможность объявления методов с переменным числом аргументов (через массивы параметров). Подобно C++, в C# позволяется перегрузка операций, а также создание структур, перечней и функций обратного вызова (посредством делегатов).

• Не требуется никаких указателей! Программы на C# обычно не требуют прямого обращения к указателям (хотя имеется возможность получить к ним доступ на более низком уровне, если вы сочтете это абсолютно необходимым).

• Автоматическое управление памятью через сборку мусора. По этой причине в C# не поддерживается ключевое слово delete.

• Формальные синтаксические конструкции для перечней, структур и свойств классов.

• Аналогичная C++ перегрузка операций для пользовательских типов, но без лишних сложностей (например, вам не требуется контролировать «возвращение *this для связывания»).

• В C# 2005 имеется возможность строить общие типы и общие члены с использованием синтаксиса, очень похожего на шаблоны C++.

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

• Полная поддержка технологии аспектно-ориентированного программирования (АОП) через атрибуты. Эта ветвь разработки позволяет назначать характеристики типам и их членам, чтобы уточнять их поведение.

Жизнь в многоязычном окружении

Что такое cts clr cls. Смотреть фото Что такое cts clr cls. Смотреть картинку Что такое cts clr cls. Картинка про Что такое cts clr cls. Фото Что такое cts clr cls

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

Одномодульные и многомодульные компоновочные блоки

Но зачем создавать многомодульные компоновочные блоки? Когда вы делите компоновочный блок на отдельные модули, вы получаете более гибкие возможности инсталляции. Например, если пользователь ссылается на удаленный компоновочный блок, то среда выполнения загрузит на его машину только необходимые модули. Поэтому вы можете сконструировать свой компоновочный блок так, чтобы редко используемые типы (например, HardDriveReformatter) были выделены в отдельный автономный модуль.

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

// Этот класс содержит точку входа приложения.

// Ждать, пока пользователь не нажмет клавишу ввода.

После того как компилятор C# (csc.exe) скомпилирует этот файл исходного кода, вы получите состоящий из одного файла компоновочный блок *.exe, который содержит манифест, CIL-инструкции и метаданные, описывающие каждый аспект классов Calc и CalcApp. Например, если вы откроете этот компоновочный блок с помощью ildasm.exe (мы рассмотрим ildasm.exe немного позже в этой же главе), вы увидите, что метод Add () в терминах CIL представляется так.

.method public hidebysig instance int32 Add(int32 x, int32 y) cil managed

Не беспокойтесь, если вы пока не в состоянии понять CIL-код для этого метода – в главе 15 будут описаны основы языка программирования CIL. Здесь следует сконцентрироваться на том, что компилятор C# генерирует CIL-код, а не специфические для платформы инструкции.

Public Function Add(ByVal x As Integer, ByVal у As Integer) As Integer

.method public instance int32 Add(int32 x, int32 y) cil managed

Преобразование CIL-кода в набор инструкций, соответствующих платформе

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

TypDefName: CalculatorExample.Calc (02000003)

Flags: [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldlnit] (00100001)

Extends: 01000001 [TypeRef] System.Object

Flags: [Public] [HideBySig] [ReuseSlot] (00000086)

(1) ParamToken: (08000001) Name: x flags: [none] (00000000)

(2) ParamToken: (08000002) Name: у flags: [none] (00000000)

Роль манифеста компоновочного блока

.publickeytoken = (B7 7A 5C 56 19 34 E0 89)

По сути, этот манифест содержит указания на внешние компоновочные блоки, необходимые для CSharpCalculator.exe (для этого используется директива.assembly extern), а также различные характеристики самого компоновочного блока (номер версии, имя модуля и т.д.).

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

Процесс построения типов класса CTS в C# будет рассматриваться в главе 4, но ряд общих характеристик типов класса приводится в табл. 1.2.

Таблица 1.2. Характеристики классов CTS

// Структуры могут содержать параметризованные конструкторы.

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

По умолчанию для каждого элемента выделяется блок памяти, соответствующий 32-битовому целому, но при необходимости это значение можно изменить (например, в случае программирования для устройств с малыми объемами памяти, таких как КПК). Спецификации CTS предполагают, что типы перечня должны «получаться» из общего базового класса, System.Enum. Из главы 3 вы узнаете, что этот базовый класс определяет ряд весьма полезных членов, которые позволяют программно извлекать, обрабатывать и преобразовывать соответствующие пары «имя-значение».

// Этот тип делегата C# может ‘указывать’ на любой метод, возвращающий

// целое значение и получающий на вход два целых значения.

public delegate int BinaryOp(int x, int y);

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

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

Таблица 1.3. Встроенные типы данных CTS

Правило 1. Правила CLS применяются только к тем компонентам типа, которые открыты для доступа за пределами определяющего их компоновочного блока.

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

// Эти открытые данные без знака не согласуются с CLS!

Но если вы используете данные без знака только внутри типа, как указано ниже

// Здесь переменная ulong используется только внутри типа,

// Указание компилятору C# выполнить проверку на соответствие CLS.

В главе 12 будут рассмотрены тонкости программирования на основе использования атрибутов, Пока что важно просто понять, что атрибут [CLSCompliant] дает компилятору C# указание проверять каждую строку программного кода на соответствие правилам CLS. Если обнаружится нарушение правил CLS, вы получите сообщение об ошибке компиляции и описание некорректного программного кода.

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

В дополнение к спецификациям CTS и CLS, последней на данный момент аббревиатурой, которую мы рассмотрим, будет аббревиатура CLR (Common Language Runtime – общеязыковая среда выполнения). Для программирования термин среда, выполнения можно понимать, как набор внешних сервисов, необходимых для выполнения данной скомпилированной единицы программного кода. Например» когда разработчик при создании нового приложения использует библиотеку базовых классов Microsoft (MFC), он знает, что для выполнения его программы потребуется соответствующий выполняемый модуль библиотеки MFC (т.е. mfc42.dll). Другие популярные языки также предлагают соответствующие выполняемые модули. Программисты VB6 привязаны к одному или двум выполняемым модулям (например, msvbvm60.dll). Разработчики Java привязаны к виртуальной машине Java (JVM) и т.д.

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

Различия между компоновочными блоками, пространствами имен и типами

Упрощенно говоря, пространство имен является группой связанных типов, содержащихся в компоновочном блоке. Например, пространство имен System.IO содержит типы, связанные с операциями ввода-вывода, пространство имен System.Data определяет основные типы для работы с базами данных и т.д. Важно понимать, что один компоновочный блок (такой как, например, mscorlib.dll) может содержать любое число пространств имен, каждое из которых может, в свою очередь, содержать любое число типов.

Чтобы ситуация стала более ясной, взгляните на рис. 1.4, на котором показан снимок окна Object Browser из Visual Studio 2005. Этот инструмент позволяет видеть компоновочные блоки, на которые ссылается текущий проект, пространства имен, содержащиеся в компоновочных блоках, типы, существующие в пределах данного пространства имен, и члены каждого типа.

Обратите внимание на то, что mscorlib.dll содержит очень много самых разных пространств имея, и в каждом из этих пространств имен содержатся свои семантически связанные типы.

Что такое cts clr cls. Смотреть фото Что такое cts clr cls. Смотреть картинку Что такое cts clr cls. Картинка про Что такое cts clr cls. Фото Что такое cts clr cls

Рис. 1.3. Модуль mscoree.dll в действии

Что такое cts clr cls. Смотреть фото Что такое cts clr cls. Смотреть картинку Что такое cts clr cls. Картинка про Что такое cts clr cls. Фото Что такое cts clr cls

Рис.1.4. Один компоновочный блок может содержать любое количество пространств имен

// Hello world на языке Managed Extensions for C++

Заметим, что здесь в любом из языков используется класс Console, определенный в пространстве имен System. Если отбросить незначительные синтаксические вариации, то эти три приложения выглядят очень похожими, как по форме, так и по логике.

Программный доступ к пространствам имен

В C# ключевое слово using упрощает ссылки на типы, определенные в данном пространстве имен. Вот как оно используется. Допустим, вы строите традиционное приложение для настольной системы. В главном окне должна отображаться некоторая диаграмма, основанная на информации, полученной от внутренней базы данных, и логотип компании. Конечно, для изучения типов в пространствах имен требуется время, но вот несколько очевидных «кандидатов», подходящих для ссылок в описанной выше программе.

// Пространства имен, необходимые для данного приложения.

using System; // Общие типы базовых классов,

using System.Drawing; // визуализация графики,

using System.Windows.Forms; // GDI-элементы,

using System.Data; // общий доступ к данным,

using System.Data.SqlClient; // доступ к данным MS SQL Server.

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

// Явный список пространств имен, используемых в данном файле.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *