Общие сведения о языке определения интерфейса Майкрософт 3.0
Язык определения интерфейса (MIDL) 3.0 — это упрощенный современный синтаксис для определения типов среды выполнения Windows в файлах языка определения интерфейсов (IDL) (.idl
файлов). Этот новый синтаксис будет знаком любому, кто столкнулся с C, C++, C#, и /или Java. MIDL 3.0 — это особенно удобный способ определения классов среды выполнения C++/Win RT
Вот как выглядит MIDL 3.0; В этом примере демонстрируется большинство элементов синтаксиса языка, которые, скорее всего, будут использоваться.
// Photo.idl
namespace PhotoEditor
{
delegate void RecognitionHandler(Boolean arg); // delegate type, for an event.
runtimeclass Photo : Windows.UI.Xaml.Data.INotifyPropertyChanged // interface.
{
Photo(); // constructors.
Photo(Windows.Storage.StorageFile imageFile);
String ImageName{ get; }; // read-only property.
Single SepiaIntensity; // read-write property.
Windows.Foundation.IAsyncAction StartRecognitionAsync(); // (asynchronous) method.
event RecognitionHandler ImageRecognized; // event.
}
}
Обратите внимание, что синтаксис MIDL 3.0 предназначен исключительно для определения типов. Вы будете использовать другой язык программирования для реализации этих типов. Чтобы использовать MIDL 3.0, вам потребуется windows SDK версии 10.0.17134.0 (Windows 10 версии 1803) (midl.exe
версии 8.01.0622 или более поздней версии, используемой с параметром /winrt
).
Примечание
Кроме того, см. консолидированную ссылку на среду выполнения Windows (системныетипа Windows и файлы метаданных Windows).
Язык определения интерфейса (IDL) начался с системы распределенных вычислений или удаленных вызовов процедур (DCE/RPC). Исходный MIDL 1.0 — DCE/RPC IDL с усовершенствованиями для определения com-интерфейсов и соклассов.
Обновленный синтаксис MIDL 2.0 (также известный как MIDLRT) был разработан в Корпорации Майкрософт для объявления API среды выполнения Windows для платформы Windows. Если вы посмотрите в папке Пакета SDK для Windows %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\winrt
, вы увидите примеры файлов .idl
, написанных с синтаксисом MIDL 2.0. Это встроенные API среды выполнения Windows, объявленные в форме двоичного интерфейса приложения (ABI). Эти файлы существуют в первую очередь для использования инструментов— вы не будете создавать и использовать эти API в этой форме (если вы не пишете очень низкий уровень кода).
См. также переход на MIDL 3.0 из классическойMIDLRT.
MIDL 3.0 — это гораздо более простой и более современный синтаксис, цель которого — объявить API среды выполнения Windows. И его можно использовать в проектах, особенно для определения классов среды выполнения C++/Win RT. Заголовки для использования из C++/WinRT для встроенных API среды выполнения Windows являются частью пакета SDK в папке %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt
.
Как правило, все API среды выполнения Windows предназначены для всех языковых проекций среды выполнения Windows. Это делается, в частности, путем выбора исключительно передачи типов среды выполнения Windows и из API среды выполнения Windows. Хотя это допустимое решение о проектировании для передачи необработанного COM-интерфейса в API среды выполнения Windows и из него, это ограничивает потребителей этого конкретного API среды выполнения Windows приложениям C++. Этот метод можно увидеть в сценариях взаимодействия, например при взаимодействии между Direct3D и XAML. Так как Direct3D находится на рисунке, сценарий обязательно сужается до приложений C++. Таким образом, API, требующий COM-интерфейса, не накладывает никаких дополнительных ограничений по сравнению с тем, что является присущим. Например, приложение C++ может получить указатель интерфейса IDXGISwapChain интерфейса, а затем передать его методу ISwapChainPanelNative::SetSwapChainChain. Например, приложение C# не сможет получить IDXGISwapChain, чтобы начать работу, так что он не сможет использовать этот метод по этой причине. Эти исключения, связанные с взаимодействием, живут в заголовках взаимодействия, таких как windows.ui.xaml.media.dxinterop.h
.
Если функции или функции COM-компонента, который вы хотите предоставить проекциям языка среды выполнения Windows за пределами C++, можно создать компонент среды выполнения Windows windows (WRC), который напрямую создает и использует com-компонент (например, DirectX), и предоставляет репликацию некоторых подмножеств компонентов и функций в виде поверхности API среды выполнения Windows, которая принимает и возвращает Windows. Только типы среды выполнения. Затем вы можете использовать этот WRC из приложения, написанного любой проекции языка среды выполнения Windows.
Основные понятия организации в определении MIDL 3.0 — это пространства имен, типы и члены. Исходный файл MIDL 3.0 (файл .idl
) содержит по крайней мере одно пространство имен, в котором находятся типы и /или подчиненные пространства имен. Каждый тип содержит ноль или больше элементов.
- Классы, интерфейсы, структуры и перечисления являются типами.
- Методы, свойства, события и поля являются примерами элементов.
При компиляции исходного файла MIDL 3.0 компилятор (midl.exe
) выдает файл метаданных среды выполнения Windows (обычно файл .winmd
).
// Bookstore.idl
namespace Bookstore
{
runtimeclass BookSku : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
BookSku();
BookSku(Single price, String authorName, String coverImagePath, String title);
Single Price;
String AuthorName{ get; };
Windows.UI.Xaml.Media.ImageSource CoverImage{ get; };
String CoverImagePath{ get; };
String Title{ get; };
Boolean Equals(BookSku other);
void ApplyDiscount(Single percentOff);
}
}
Так как пространство имен типа среды выполнения Windows становится частью имени типа, приведенный выше, определяет класс среды выполнения с именем Bookstore.BookSku. Нет языка независимо от языка способ выражения BookSku без выражения пространства имен.
Этот класс реализует интерфейс Windows.UI.Xaml.Data.INotifyPropertyChanged. А класс содержит несколько элементов: два конструктора, свойство чтения и записи (Price), некоторые свойства только для чтения (AuthorName через Title) и два метода с именем Равно и ApplyDiscount. Обратите внимание на использование типа Single вместо float. И это String имеет верхний регистр "S".
Совет
Visual Studio предоставляет лучший интерфейс для компиляции MIDL 3.0 с помощью расширения Visual Studio C++/WinRT (VSIX). См. поддержку Visual Studio для C++/WinRT иVSIX.
Но вы также можете скомпилировать MIDL 3.0 из командной строки. Если исходный код этого примера хранится в файле с именем Bookstore.idl
, можно выполнить следующую команду. При необходимости можно обновить номер версии пакета SDK, используемый в команде (10.0.17134.0).
midl /winrt /metadata_dir "%WindowsSdkDir%References\10.0.17134.0\windows.foundation.foundationcontract\3.0.0.0" /h "nul" /nomidl /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd" /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\Windows.Foundation.UniversalApiContract.winmd" /reference "%WindowsSdkDir%\References\10.0.17134.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd" Bookstore.idl
Средство midl.exe
компилирует пример и создает файл метаданных с именем Bookstore.winmd
(по умолчанию используется имя файла .idl
).
Совет
Если вы используете несколько файлов IDL (для получения рекомендаций об этом, ознакомьтесь с классами среды выполнения Factoring в midl-файлах (idl)), а затем объединить все полученные .winmd
файлы в один файл с тем же именем, что и корневое пространство имен. Этот окончательный .winmd
файл будет тем, на который будут ссылаться потребители API.
В этом случае BookSku является единственным классом среды выполнения в пространстве имен Bookstore, поэтому мы сохранили шаг и только что назвали файл .idl
для пространства имен.
Кстати, можно использовать команду where
, чтобы узнать, где установлен midl.exe
.
where midl
Если вы хотите использовать типы, определенные в одном файле .idl
из другого файла .idl
, используйте директиву import
. Дополнительные сведения и пример кода см. в элементах управления XAML; привязка к свойству C++/WinRT. Конечно, если вы используете встроенный или сторонний компонент, то у вас нет доступа к файлу .idl
. Например, может потребоваться использовать API среды выполнения Windows Win2D для немедленной отрисовки графики в режиме 2D. Приведенная выше команда использовала параметр /reference
для ссылки на файл метаданных среды выполнения Windows (.winmd
). В следующем примере мы снова будем использовать этот переключатель, создав сценарий, в котором у нас есть Bookstore.winmd
, но не Bookstore.idl
.
// MVVMApp.idl
namespace MVVMApp
{
runtimeclass ViewModel
{
ViewModel();
Bookstore.BookSku BookSku{ get; };
}
}
Если исходный код для приведенного выше примера хранится в файле с именем MVVMApp.idl
, можно выполнить следующую команду, чтобы ссылаться на Bookstore.winmd
.
midl /winrt /metadata_dir "%WindowsSdkDir%References\10.0.17134.0\windows.foundation.foundationcontract\3.0.0.0" /h "nul" /nomidl /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd" /reference "%WindowsSdkDir%References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\Windows.Foundation.UniversalApiContract.winmd" /reference "%WindowsSdkDir%\References\10.0.17134.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd" /reference Bookstore.winmd MVVMApp.idl
Требуется пространство имен. Он префиксирует имя всех типов, определенных в области блока пространства имен с именем пространства имен. Пространство имен также может содержать объявления подчиненного пространства имен. Имя типов, определенных в подчиненной области пространства имен, имеет префикс всех содержащих имен пространств имен.
Приведенные ниже примеры — два способа объявления того же класса Windows.Foundation.Uri (как вы видите, периоды разделения уровней вложенных пространств имен).
namespace Windows.Foundation
{
runtimeclass Uri : IStringable
{
...
}
}
namespace Windows
{
namespace Foundation
{
runtimeclass Uri : IStringable
{
...
}
}
}
Ниже приведен еще один пример, показывающий, что он является законным для объявления пространств имен и их типов в вложенном виде.
namespace RootNs.SubNs1
{
runtimeclass MySubNs1Class
{
void DoWork();
}
namespace SubNs2
{
runtimeclass MySubNs2Class
{
void DoWork();
}
}
}
Но это более распространенная практика закрытия предыдущего пространства имен и открытия нового, как это.
namespace RootNs.SubNs1
{
runtimeclass MySubNs1Class
{
void DoWork();
}
}
namespace RootNs.SubNs1.SubNs2
{
runtimeclass MySubNs2Class
{
void DoWork();
}
}
Существует два типа данных в MIDL 3.0: типы значений и ссылочные типы. Переменная типа значения непосредственно содержит свои данные. Переменная ссылочного типа сохраняет ссылку на свои данные (такая переменная также называется объектом ).
Для двух переменных ссылочного типа можно ссылаться на один и тот же объект. Таким образом, операция с одной переменной влияет на объект, на который ссылается другая переменная. При использовании типов значений переменные имеют собственную копию данных, и это невозможно для операции с одной, чтобы повлиять на другую.
Типы значений MIDL 3.0 разделяются на простые типы, типы перечисления, типы структур и типы, допускающие значение NULL.
Ссылочные типы MIDL 3.0 делятся на типы классов, типы интерфейсов и типы делегатов.
Ниже приведен обзор системы типов MIDL 3.0. В отличие от предыдущих версий MIDL, для этих типов нельзя использовать псевдонимы.
Категория | Описание | |
---|---|---|
Типы значений | Простые типы | Подписанный целочисленный элемент: Int16, Int32, Int64 |
Целочисленный без знака: UInt8, UInt16, UInt32, UInt64 | ||
Символы Юникода: Char (представляет UTF-16LE; 16-разрядную единицу кода Юникода) | ||
Строки Юникода: строка | ||
С плавающей запятой IEEE: single, Double | ||
Логическое значение: логические | ||
128-разрядная UUID: Guid | ||
Типы перечисления | Определяемые пользователем типы формы перечисления E {...} | |
Типы структур | Определяемые пользователем типы формы структуры S {...} | |
Типы, допускающие значение NULL | Расширения всех других типов значений с значением null | |
Ссылочные типы | Типы классов | Конечный базовый класс всех других типов: Object |
Определяемые пользователем типы формы runtimeclass C {...} | ||
Типы интерфейсов | Определяемые пользователем типы интерфейса формы I {...} | |
Типы делегатов | Определяемые пользователем типы делегата <returnType> D(...) |
Семь целочисленных типов обеспечивают поддержку 8-разрядных неподписанных данных; и 16-разрядные, 32-разрядные и 64-разрядные значения в форме со знаком или без знака.
Два типа с плавающей запятой, single и Double, представляют данные с использованием 32-разрядных одноточийных и 64-разрядных форматов IEEE 754, соответственно.
Логическое логическое типа MIDL 3.0 представляет логические значения; либо true
, либо false
.
Символы и строки в MIDL 3.0 содержат символы Юникода. Тип Char представляет единицу кода UTF-16LE; и тип String представляет последовательность единиц кода UTF-16LE.
В следующей таблице перечислены числовые типы MIDL 3.0.
Категория | Биты | Тип | Диапазон и точность |
---|---|---|---|
Подписанный целочисленный | 16 | Int16 | –32,768...32,767 |
32 | Int32 | –2,147,483,648...2,147,483,647 | |
64 | Int64 | –9,223,372,036,854,775,808...9,223,372,036,854,775,807 | |
Целочисленный без знака | 8 | UInt8 | 0...255 |
16 | UInt16 | 0...65,535 | |
32 | UInt32 | 0...4,294,967,295 | |
64 | UInt64 | 0...18,446,744,073,709,551,615 | |
Плавающая точка | 32 | одиночный | 1.5 × 10–45 до 3,4 × 1038, 7-разрядная точность |
64 | Double | 5.0 × 10–324 до 1,7 × 10308, 15-разрядная точность |
Исходные файлы MIDL 3.0 используют определения типов для создания новых типов. Определение типа указывает имя и члены нового типа. Эти категории типов MIDL 3.0 являются определяемыми пользователем.
- типы атрибутов,
- Типы структур,
- типы интерфейсов,
- Типы runtimeclass,
- Типы делегатов и
- Типы перечисления.
Атрибут определяет атрибут среды выполнения Windows, который можно применить к другим определениям типов. Атрибут предоставляет метаданные о типе, к которому применяется атрибут.
Структура определяет структуру среды выполнения Windows, содержащую элементы данных (поля). Структуры — это типы значений, и они не требуют выделения кучи. Элемент данных типа структуры должен быть типом значения или типом, допускаемым значением NULL. Типы структур не поддерживают наследование.
Интерфейс определяет интерфейс среды выполнения Windows, который является именованным набором элементов функции. Интерфейс может указать, что реализация интерфейса также должна реализовывать один или несколько указанных дополнительных (обязательных) интерфейсов. Каждый тип интерфейса напрямую является производным от интерфейса среды выполнения Windows интерфейсе IInspectable.
Тип runtimeclass определяет класс среды выполнения Windows (класс среды выполнения). Класс среды выполнения содержит элементы, которые могут быть свойствами, методами и событиями.
Тип делегата определяет делегат среды выполнения Windows, который представляет ссылку на метод с определенным списком параметров и типом возврата. Делегаты позволяют рассматривать метод как сущность, которую можно передать в качестве параметра. Делегат аналогичен концепции указателя функции, найденного на некоторых других языках. В отличие от указателей функций, делегаты являются объектно-ориентированными и типобезопасны.
Тип перечисления — это отдельный тип с именованными константами. Каждый тип перечисления имеет неявный базовый тип; Int32 или UInt32. Набор значений типа перечисления совпадает с набором значений базового типа.
MIDL 3.0 поддерживает три дополнительные категории типов.
- одномерные типы массивов,
- Типы значений, допускающие значение NULL, и
- тип объекта
.
Прежде чем его можно использовать, не нужно объявлять одномерный массив. Вместо этого типы массивов создаются по имени типа с квадратными скобками. Например, Int32[] является одномерным массивом Int32.
Аналогичным образом, типы значений, допускающие значение NULL, также не должны быть определены до их использования. Для каждого ненулевого типа значения null
. См. также IReference<T>.
Наконец, MIDL 3.0 поддерживает тип объекта
В MIDL 3.0 можно использовать только выражение в определении значения именованных констант перечисленного типа; другими словами, в инициализаторе перечисления.
Выражение создается из операндов и операторов. Операторы в выражении указывают, какие операции применяются к операндам. Примеры операторов: +, -, *, /и new
. Примеры операндов включают литералы, поля, локальные переменные и выражения.
Если выражение содержит несколько операторов, приоритет операторов определяет порядок оценки отдельных операторов. Например, выражение x + y * z оценивается как x + (y * z), так как оператор * имеет более высокий приоритет, чем оператор +. Логические операции являются более низким приоритетом, чем побитовые операции.
В следующей таблице приведены операторы MIDL 3.0, в котором перечислены категории операторов в порядке приоритета от самого высокого до самого низкого. Операторы в той же категории имеют равный приоритет.
Категория | Выражение | Описание |
---|---|---|
Первичный | x++ | Приращение после добавления |
x-- | Пост-декремент | |
Одинарный | +x | Тождество |
-x | Отрицание | |
!x | Логическое отрицание | |
~x | Битовое отрицание | |
++x | Предварительный шаг | |
--x | Предварительный декремент | |
Мультипликативные | x * y | Умножение |
x / y | Деление | |
x % y | Остаток | |
Присадка | x + y | Добавление, объединение строк, сочетание делегатов |
x – y | Вычитание, удаление делегата | |
Сдвиг | x << y | Сдвиг влево |
x >> y | Сдвиг вправо | |
Битовое И | x & y | Целочисленная битовая и |
Битовая XOR | x ^ y | Целочисленный битовый XOR |
Битовое ИЛИ | x | y | Целочисленный битовый ИЛИ |
Логический И | x && y | Логический и логический |
Логическое ИЛИ | x || y | Логический ИЛИ логический |
классы (или классы среды выполнения) являются самыми основными типами MIDL 3.0. Класс — это определение агрегирования методов, свойств и событий в одном модуле. Классы поддерживают наследования и полиморфизма— механизмы, в которых производные классы могут расширять и специализировать базовых классов.
Вы определяете новый тип класса с помощью определения класса. Определение класса начинается с заголовка, указывающего ключевое слово runtimeclass
, имя класса, базовый класс (если задано), а также интерфейсы, реализованные классом. За заголовком следует текст класса, состоящий из списка объявлений членов, написанных между разделителями { и }.
Ниже приведено определение простого класса с именем Area.
runtimeclass Area
{
Area(Int32 width, Int32 height);
Int32 Height;
Int32 Width;
static Int32 NumberOfAreas { get; };
}
Это определяет новый класс среды выполнения Windows с именем Area, который имеет конструктор, который принимает два параметра Int32, два свойства Int32 записи с именем Height и Width, а также статическое свойство только для чтения с именем NumberOfAreas.
По умолчанию класс среды выполнения запечатан, а производный от него запрещен. См. базовых классов.
Чтобы привязать XAML к модели представления, класс среды выполнения модели представления должен быть определен в MIDL. См. элементы управления XAML; привязывается к свойству C++/WinRT для получения дополнительных сведений.
Можно объявить, что класс не поддерживает экземпляры (и поэтому должен содержать только статические члены), префиксируя определение класса среды выполнения с помощью ключевого слова static
. Добавление нестатитического члена в класс вызывает ошибку компиляции.
static runtimeclass Area
{
static Int32 NumberOfAreas { get; };
}
Статический класс отличается от пустого класса. См. также пустые классы.
Можно указать, что определение класса является неполным, префиксируя определение класса среды выполнения с помощью ключевого слова partial
. Все определения разделяемого класса, встречаемые компилятором, объединяются в один класс среды выполнения. Эта функция в основном предназначена для сценариев разработки XAML, в которых некоторые из частичных классов создаются машинным образом.
Модификатор | Значение |
---|---|
статический | Класс не имеет экземпляров. Следовательно, разрешены только статические члены. |
частичный | Определение класса является неполным. |
Дополнительные модификаторы см. в
Так как MIDL 3.0 является языком определения для описания общедоступной поверхности типов среды выполнения Windows, нет необходимости явного синтаксиса объявлять общедоступную доступность члена. Все члены неявно открыты. Вот почему MIDL 3.0 не требует и не разрешает (эффективно избыточное) ключевое слово public
.
Определение класса может указывать базовый класс, следуя параметрам имени и типа класса с двоеточием и именем базового класса. Опущение спецификации базового класса совпадает с типом Object (другими словами, из IInspectable).
Примечание
Классы модели представления ( на самом деле, любой класс среды выполнения, определяемые в приложении), не должны быть производными от базового класса.
Любой класс среды выполнения, определяемый в приложении, который является производным от базового класса, называется классом составной. Существуют ограничения для составных классов. Чтобы приложение передало комплект сертификации приложений Windows тесты, используемые Visual Studio и Microsoft Store для проверки отправки (и поэтому для успешного приема приложения в Microsoft Store), составной класс должен в конечном итоге быть производным от базового класса Windows. Это означает, что класс в самом корне иерархии наследования должен быть типом, происходящим в пространстве имен Windows.* .
См. элементы управления XAML; привязывается к свойству C++/WinRT для получения дополнительных сведений.
В следующем примере базовый класс Volume — Area, а базовый класс Area — Windows.UI.Xaml.DependencyObject.
unsealed runtimeclass Area : Windows.UI.Xaml.DependencyObject
{
Area(Int32 width, Int32 height);
Int32 Height;
Int32 Width;
}
runtimeclass Volume : Area
{
Volume(Int32 width, Int32 height, Int32 depth);
Int32 Depth;
}
Примечание
Здесь области и тома определяются в том же исходном файле. Сведения о преимуществах и минусах см. в разделе классы среды выполнения Factoring в midl-файлах (IDL).
Класс наследует члены базового класса. Наследование означает, что класс неявно содержит все члены базового класса, за исключением конструкторов базового класса. Производный класс может добавлять новые члены в наследуемые элементы, но не может удалить определение наследуемого элемента.
В предыдущем примере
Как правило, правила разрешения типов требуют, чтобы имя типа было полностью указано при ссылке. Исключение заключается в том, что тип определен в том же пространстве имен, что и текущий тип. Приведенный выше пример работает, если области и тома находятся в одном пространстве имен.
Определение класса также может указывать список интерфейсов, реализуемых классом. Интерфейсы указываются в виде разделенного запятыми списка интерфейсов после базового класса (необязательно).
В приведенном ниже примере класс
unsealed runtimeclass Area : Windows.Foundation.IStringable
{
Area(Int32 width, Int32 height);
Int32 Height;
Int32 Width;
}
runtimeclass Volume : Area, Windows.Foundation.IStringable, IEquatable
{
Volume(Int32 width, Int32 height, Int32 depth);
Int32 Depth;
}
В MIDL вы не объявляете члены интерфейса в классе. Конечно, необходимо объявить и определить их по фактической реализации.
Члены класса — это статические члены или членов экземпляра. Статический член принадлежит классу. Член экземпляра принадлежит объекту (т. е. экземпляру класса).
В этой таблице показаны типы элементов, которые может содержать класс.
Тип члена | Описание |
---|---|
Конструкторы | Действия, необходимые для инициализации экземпляра класса или инициализации самого класса |
Свойства | Действия, связанные с чтением и записью именованных свойств экземпляра класса или самого класса |
Методика | Вычисления и действия, которые могут выполняться экземпляром класса или самим классом. |
События | Уведомления, которые могут быть вызваны экземпляром класса |
MIDL 3.0 поддерживает объявление конструкторов экземпляров. Конструктор экземпляра — это метод, реализующий действия, необходимые для инициализации экземпляра класса. Конструкторы могут не быть статическими.
Конструктор объявляется как метод экземпляра (но без возвращаемого типа) и с тем же именем, что и содержащий класс.
Конструкторы экземпляров могут быть перегружены. Например, класс теста
runtimeclass Test
{
Test();
Test(Int32 x);
Test(Double x, Double y);
}
Дополнительные сведения о синтаксисе списков параметров см. в разделе Методы ниже.
Свойства экземпляра, методы и события наследуются. Конструкторы экземпляров не наследуются (с одним исключением), а класс не имеет конструкторов экземпляров, отличных от фактически объявленных в классе. Если конструктор экземпляра не указан для класса, вы не сможете напрямую создать экземпляр класса. Для такого класса обычно используется метод фабрики, возвращающий экземпляр класса.
Исключение — это неуправляемые классы. Неуправляемый класс может иметь один или несколько защищенных конструкторов.
свойства концептуально похожи на поля (например, поля C# или поля структуры MIDL 3.0). Оба свойства и поля являются элементами с именем и соответствующим типом. Однако в отличие от полей свойства не указывают места хранения. Вместо этого свойства имеют методы доступа, которые указывают функцию, выполняемую при чтении или записи свойства.
Свойство объявляется как поле структуры, за исключением того, что объявление заканчивается ключевым словом get
и/или ключевым словом set
, написанным между разделителями { и }, и заканчивается точкой с запятой.
Свойство с ключевым словом get
и ключевым словом set
является свойством чтения и записи. Свойство, которое имеет только ключевое слово get
, является свойством только для чтения. Среда выполнения Windows не поддерживает свойства только для записи.
Например, класс Area, который ранее видел, содержит два свойства записи с именем Height и Width.
unsealed runtimeclass Area
{
Int32 Height { get; set; };
Int32 Width; // get and set are implied if both are omitted.
}
Объявление Width пропускает фигурные скобки и ключевые слова get
и set
. Упущение подразумевает, что свойство является чтением и записью и семантической идентично предоставлению ключевых слов get
и set
в этом порядке —get
, а затем set
.
Кроме того, можно указать только ключевое слово get
, чтобы указать, что свойство доступно только для чтения.
// Read-only instance property returning mutable collection.
Windows.Foundation.Collections.IVector<Windows.UI.Color> Colors { get; };
Среда выполнения Windows не поддерживает свойства только для записи. Но можно указать только ключевое слово set
, чтобы изменить существующее свойство только для чтения в свойство чтения и записи. Рассмотрим эту версию Area в качестве примера.
unsealed runtimeclass Area
{
...
Color SurfaceColor { get; };
}
Если вы хотите сделать SurfaceColor свойством read-write, и вам не нужно поддерживать двоичную совместимость с предыдущими определениями Area (например, класс Area является типом в приложении, которое вы повторно компилируете каждый раз), то можно просто добавить ключевое слово set
в существующее объявление SurfaceColor, как это.
unsealed runtimeclass Area
{
...
Color SurfaceColor { get; set; };
}
Если с другой стороны, требуется двоичная стабильность (например, класс Area является компонентом библиотеки, которую вы отправляете клиентам), то нельзя добавить ключевое слово set
в существующее объявление свойств. Это изменяет двоичный интерфейс в класс.
В этом случае добавьте ключевое слово set
свойства в дополнительное определение свойства в конце класса, как это.
unsealed runtimeclass Area
{
...
Color SurfaceColor { get; };
...
Color SurfaceColor { set; };
}
Компилятор создает ошибку для свойства только для записи. Но это не то, что делается здесь. Из-за предыдущего объявления свойства только для чтения добавление ключевого слова set не объявляет свойство только для записи, а вместо свойства чтения и записи.
Реализация среды выполнения Windows является одним или двумя методами доступа в интерфейсе. Порядок получения и задания ключевых слов в объявлении свойства определяет порядок методов получения и задания доступа в интерфейсе резервного копирования.
Метод доступа get
соответствует методу без параметров с возвращаемым значением типа свойства — методом получения свойства.
Метод доступа set
соответствует методу с одним параметром с именем значением, а возвращаемый тип — метод задания свойств.
Следовательно, эти два объявления создают разные двоичные интерфейсы.
Color SurfaceColor { get; set; };
Color SurfaceColor { set; get; };
Аналогично методам, MIDL 3.0 поддерживает как свойства экземпляра, так и статические свойства. Статические свойства объявляются с префиксом модификатора static
, а свойства экземпляра объявляются без него.
Метод является членом, реализующим вычисление или действие, которое может выполняться экземпляром класса или самим классом. Доступ к статическим методом осуществляется через класс. Доступ к методу экземпляра
Метод имеет (возможно, пустой) список параметров , представляющих значения или ссылки на переменные, передаваемые методу. Метод также имеет тип возвращаемого типа, который указывает тип вычисляемого значения и возвращаемого методом. Возвращаемый тип метода void
, если он не возвращает значение.
// Instance method with no return value.
void AddData(String data);
// Instance method *with* a return value.
Int32 GetDataSize();
// Instance method accepting/returning a runtime class.
// Notice that you don't say "&" nor "*" for reference types.
BasicClass MergeWith(BasicClass other);
// Asynchronous instance methods.
Windows.Foundation.IAsyncAction UpdateAsync();
Windows.Foundation.IAsyncOperation<Boolean> TrySaveAsync();
// Instance method that returns a value through a parameter.
Boolean TryParseInt16(String input, out Int16 value);
// Instance method that receives a reference to a value type.
Double CalculateArea(ref const Windows.Foundation.Rect value);
// Instance method accepting or returning a conformant array.
void SetBytes(UInt8[] bytes);
UInt8[] GetBytes();
// instance method that writes to a caller-provided conformant array
void ReadBytes(ref UInt8[] bytes);
сигнатуры метода должны быть уникальными в классе, в котором объявлен метод. Сигнатура метода состоит из имени метода, типов его параметров и /или числа его параметров. Подпись метода не включает тип возвращаемого значения.
Метод может иметь один из двух необязательных модификаторов видимости, если метод присутствует в производном классе.
переопределенным модификатором утверждает, что этот метод может быть переопределен методом (с тем же именем и сигнатурой), принадлежащим подклассу.
Модификатор , защищенный, утверждает, что этот метод доступен только элементами в последующем производном классе.
Метод перегрузки позволяет нескольким методам в одном классе иметь то же имя, если их параметры отличаются числом (другими словами, методы имеют разные arity).
runtimeclass Test
{
static void F();
static void F(Double x);
static void F(Double x, Double y);
}
Примечание
Все методы с одинаковым именем должны иметь разные arity. Это связано с тем, что слабо типизированные языки программирования не поддерживают перегрузку по типу.
параметры используются для передачи значений или переменных ссылок на метод. Параметр описывает слот с типом и именем, а также при необходимости некоторые ключевые слова модификатора. Аргумент — это фактическое значение, переданное в этом слоте от вызывающего метода вызывающей стороны.
Параметры метода получают их значение из определенного аргумента , указанного при вызове метода. Способ передача аргументов между вызывающим и вызывающим абонентом зависит от типа параметра. По умолчанию все параметры являются входных параметров, то есть они маршалируются только от вызывающего объекта к вызывающей стороны. Ключевые слова модификатора ref
, ref const
и out
можно добавить для изменения направления маршалинга по умолчанию между вызывающим и вызывающим, а также создания выходных параметров. Хотя не все ключевые слова допустимы со всеми типами параметров; Допустимые сочетания подробно описаны ниже.
Важно!
Среда CLR содержит основные понятия и ключевые слова модификатора, которые, как представляется, похожи на те, которые описаны в этом разделе. Однако на практике они не связаны, и влияние этих модификаторов зависит от проектирования и функционирования среды выполнения Windows.
Типы значений неявно входных параметров, и по умолчанию копия аргумента передается из вызывающего объекта вызывающей стороны. Параметры значения можно преобразовать в выходные параметры с ключевым словом out
; В этом случае аргумент маршалируется вместо вызываемого участника только вызывающей стороне.
runtimeclass Test
{
static void Divide(Int32 x, Int32 y, out Int32 result, out Int32 remainder);
}
В качестве специальной оптимизации производительности типы структур (и ни один другой тип), которые обычно передаются по значению в виде полной копии, можно передать указателем на неизменяемую структуру. Это достигается с помощью ключевого слова ref const
(неconst ref
), который помечает параметр структуры как входной параметр, но предписывает маршалеру передать указатель на хранилище структуры вместо передачи полной копии структуры. Обратите внимание, что структуру неизменяемо; Указатель является концептуально указателем константов. Бокс не участвует. Это практический выбор при принятии значения как Matrix4x4, например.
runtimeclass Test
{
static Boolean IsIdentity(ref const Windows.Foundation.Numerics.Matrix4x4 m);
}
Ссылочные типы также являются неявными входными параметрами, что означает, что вызывающий отвечает за выделение объекта и передачу ссылки на него в качестве аргумента; однако поскольку аргумент является ссылкой на объект, изменения этого объекта вызывающим объектом наблюдаются вызывающим объектом после вызова. Кроме того, можно сделать выходной параметр с ключевым словом out
. В этом случае роли будут отменены; Вызывающий объект — это тот, который выделяет объект и возвращает его обратно вызывающему объекту. Опять же, ключевые слова ref
нельзя использовать в целом с ссылочными типами (см. исключение ниже).
runtimeclass Test
{
static void CreateObjectWithConfig(Config config, out MyClass newObject);
}
В следующей таблице приведены сведения о поведении ключевых слов маршалинга для параметров значения и ссылочных параметров:
Поведение | Выделено по | Ключевое слово | Типы | Замечания |
---|---|---|---|---|
Входной параметр | Посетитель | (нет) | Все типы | Поведение по умолчанию |
ref const |
Только структуры | Оптимизация производительности | ||
Выходной параметр | Вызывающий | out |
Все типы |
Среда выполнения Windows поддерживает типы массивов, поведение которых в качестве параметра несколько отличается. Массив — это структура данных, содержащая ряд переменных, хранящихся последовательно и доступ к которым осуществляется через индекс. Переменные, содержащиеся в массиве, также называемые элементами массива, являются одинаковыми, и этот тип называется типом элемента массива.
MIDL 3.0 поддерживает объявления одномерногомассива
Параметр массива является ссылочным типом, и, как и все ссылочные типы, по умолчанию являются входным параметром. В этом случае вызывающий объект выделяет массив вызывающему объекту, который может считывать его элементы, но не может изменять их (только для чтения). Это называется шаблоном передачи массива. Кроме того, шаблон
runtimeclass Test
{
// Pass array pattern: read-only array from caller to callee
void PassArray(Int32[] values);
// Fill array pattern: caller allocates array for callee to fill
void FillArray(ref Int32[] values);
// Receive array pattern: callee allocates and fill an array returned to caller
void ReceiveArray(out Int32[] values);
}
В следующей таблице приведены сведения о поведении массивов и их элементов:
Шаблон массива | Ключевое слово | Выделено по | Доступ к элементам с помощью вызываемого объекта |
---|---|---|---|
"Pass array" (Передача массива) | (нет) | Посетитель | Только для чтения |
"Массив заливки" | ref |
Посетитель | Только запись |
"Получение массива" | out |
Вызывающий | Чтение и запись |
Дополнительные сведения об использовании параметров массива в стиле C (также известных как соответствующие массивы) с помощью C++/WinRT см. в параметрах массива.
Метод, объявленный с префиксом модификатора static
, является статическим методом. Статический метод не имеет доступа к конкретному экземпляру и поэтому может напрямую обращаться только к другим статическим членам класса.
Метод, объявленный без модификатора static
, является методом экземпляра.
Метод экземпляра имеет доступ к конкретному экземпляру и может получить доступ как к статическим, так и к элементам экземпляра класса.
Следующий класс Entity содержит как статические, так и элементы экземпляра.
runtimeclass Entity
{
Int32 SerialNo { get; };
static Int32 GetNextSerialNo();
static void SetNextSerialNo(Int32 value);
}
Каждый экземпляр сущности сущности содержит собственный серийный номер (и предположительно некоторые другие сведения, которые не отображаются здесь). Внутри системы конструктор сущности (который похож на метод экземпляра) инициализирует новый экземпляр со следующим доступным серийным номером.
Свойство SerialNo
Статические методы GetNextSerialNo и SetNextSerialNo могут получить доступ к внутреннему следующего доступного серийного номера статического члена класса Entity.
Все методы в типе среды выполнения Windows являются фактически виртуальными. При вызове виртуального метода тип времени выполнения экземпляра, для которого выполняется вызов, определяет фактическую реализацию метода для вызова.
Метод можно переопределить в производном классе. Если объявление метода экземпляра включает модификатор overridable
, метод можно переопределить производными классами. Определяется ли производный класс фактически переопределением переопределенного метода базового класса. Он отсутствует в метаданных. Если производный класс переопределяет метод в базовом классе, он объявляет новый метод, который находится рядом с производным методом класса, а не переопределяет его.
Если объявление метода экземпляра включает модификатор protected
, метод виден только производным классам.
Объявление события является членом, указывающим, что класс является источником событий. Такой источник событий предоставляет уведомления любому получателю, реализующим делегат (метод с определенной подписью).
Вы объявляете событие с помощью ключевого слова event
, за которым следует имя типа делегата (описывающее требуемую подпись метода), а затем имя события. Ниже приведен пример события, использующего существующий тип делегата из платформы.
runtimeclass Area
{
...
event Windows.UI.Xaml.WindowSizeChangedEventHandler SizeChanged;
...
}
Объявление события неявно добавляет два метода в класс: добавить метод, который клиент вызывает для добавления обработчика событий в источник, а удалить метод, который клиент вызывает для удаления ранее добавленного обработчика событий. Ниже приведены дополнительные примеры.
// Instance event with no meaningful payload.
event Windows.Foundation.TypedEventHandler<BasicClass, Object> Changed;
// Instance event with event parameters.
event Windows.Foundation.TypedEventHandler<BasicClass, BasicClassSaveCompletedEventArgs> SaveCompleted;
// Static event with no meaningful payload.
static event Windows.Foundation.EventHandler<Object> ResetOccurred;
// Static event with event parameters.
static event Windows.Foundation.EventHandler<BasicClassDeviceAddedEventArgs> DeviceAdded;
По соглашению два параметра всегда передаются обработчику событий среды выполнения Windows: идентификатор отправителя и объект аргументов событий. Отправитель — это объект, который вызвал событие или значение NULL для статических событий. Если событие не имеет значимых полезных данных, аргументы события — это объект, значение которого равно NULL.
Тип делегата задает метод с определенным списком параметров и типом возврата. Один экземпляр события может содержать любое количество ссылок на экземпляры своего типа делегата. Объявление аналогично обычному методу-члену, за исключением того, что оно существует вне класса среды выполнения, и оно префиксируется с помощью ключевого слова delegate
.
Делегат позволяет рассматривать методы как сущности, которые могут быть назначены переменным и переданы в качестве параметров. Делегаты похожи на концепцию указателей функций, найденных на некоторых других языках. Но, в отличие от указателей функций, делегаты являются объектно-ориентированными и типобезопасны.
Если мы не хотим использовать тип делегата WindowSizeChangedEventHandler из платформы, то можно определить собственный тип делегата.
delegate void SizeChangedHandler(Object sender, Windows.UI.Core.WindowSizeChangedEventArgs args);
Экземпляр типа делегата SizeChangedHandler может ссылаться на любой метод, который принимает два аргумента (объект и WindowSizeChangedEventArgs) и возвращает void. После обсуждения структурвы также сможете заменить параметр WindowSizeChangedEventArgs событием типа.
Интересное и полезное свойство делегата заключается в том, что он не знает или заботится о классе метода, на который он ссылается; все, что важно, заключается в том, что указанный метод имеет одинаковые параметры и тип возвращаемого значения, что и делегат.
При необходимости можно атрибутировать объявление делегата с помощью [uuid(...)]
.
См. также делегатов, возвращающихHRESULT.
Структура — это структура данных, которая может содержать элементы данных (поля). Но, в отличие от класса, структуру является типом значения.
Структуры особенно полезны для небольших структур данных, имеющих семантику значений. Сложные числа или точки в системе координат являются хорошими примерами структур. Использование структур, а не классов для небольших структур данных может значительно отличаться от количества выделений памяти, которые выполняет приложение.
Рассмотрим пример для контрастности классов и структур. Ниже приведена версия Point в качестве класса .
runtimeclass Point
{
Point(Int32 x, Int32 y);
Int32 x;
Int32 y;
}
Эта программа C# создает и инициализирует массив из 100 экземпляров Point. С помощью Point реализованы как класс, создается экземпляр отдельных объектов 101: один для самого объекта массива; и по одному для каждого из 100 элементов Point.
class Test
{
static Test()
{
Point[] points = new Point[100];
for (Int32 i = 0; i < 100; ++i) points[i] = new Point(i, i);
}
}
Более эффективная альтернатива — сделать Point структурой вместо класса.
struct Point
{
Int32 x;
Int32 y;
};
Теперь создается экземпляр только одного объекта — сам объект массива. Элементы Point хранятся в строке внутри массива; расположение памяти, которое кэши процессора могут использовать для мощного эффекта.
Изменение структуры — это двоичное критическое изменение. Поэтому структуры, реализованные как часть самой Windows, не изменяются после внедрения.
Интерфейс определяет контракт, который можно реализовать классами. Интерфейс может содержать методы, свойства и события, как классы.
В отличие от класса, интерфейс не предоставляет реализации определяемых им элементов. Он просто указывает элементы, которые должны быть предоставлены любым классом, реализующим интерфейс.
Интерфейсы могут требовать класс, реализующий интерфейс для реализации других интерфейсов. В следующем примере интерфейс IComboBox требует, чтобы любой класс, реализующий IComboBox, также реализует ITextBox и IListBox. Кроме того, класс, реализующий IComboBox, также должен реализовывать IControl. Это связано с тем, что для ITextBox и IListBox требуется .
interface IControl
{
void Paint();
}
interface ITextBox requires IControl
{
void SetText(String text);
}
interface IListBox requires IControl
{
void SetItems(String[] items);
}
interface IComboBox requires ITextBox, IListBox
{
...
}
Класс может реализовать ноль или больше интерфейсов. В следующем примере класс EditBox реализует IControl и IDataBound.
interface IDataBound
{
void Bind(Binder b);
}
runtimeclass EditBox : IControl, IDataBound
{
}
Для типов среды выполнения Windows на платформе Windows интерфейс определяется, если разработчики, использующие эти типы, должны реализовать интерфейс. Другой вариант использования для определения интерфейса заключается в том, что несколько классов среды выполнения реализуют интерфейс, и разработчики, использующие эти классы среды выполнения, будут получать доступ к различным типам объектов универсально (и таким образом полиморфно) через этот общий интерфейс.
Примечание
Дважды думайте об использовании ключевого слова requires
в MIDL 3.0. Это может привести к беспорядочному проектированию, особенно при учете управления версиями.
Тип перечисления
enum Color
{
Red,
Green,
Blue, // Trailing comma is optional, but recommended to make future changes easier.
};
Каждый тип перечисления имеет соответствующий целочисленный тип, называемый базовым типом типа перечисления. Базовый тип перечисления — Int32 или UInt32.
Среда выполнения Windows поддерживает два типа перечислений: обычные перечисления и флаги перечисления. Перечисление нормального вида выражает набор эксклюзивных значений; хотя один из флагов представляет набор логических значений. Чтобы включить побитовые операторы для перечисления флагов, компилятор MIDL 3.0 создает перегрузки операторов C++.
Перечисление флагов применяет атрибут [flags]
. В этом случае базовый тип перечисления — UInt32. Если атрибут [flags]
отсутствует (обычный перечисление), базовый тип перечисления Int32. Невозможно объявить перечисление как любой другой тип.
[flags]
enum SetOfBooleanValues
{
None = 0x00000000,
Value1 = 0x00000001,
Value2 = 0x00000002,
Value3 = 0x00000004,
};
Формат хранилища и диапазон возможных значений типа перечисления определяются его базовым типом. Набор значений, которые может принимать тип перечисления, не ограничивается его объявленными элементами перечисления.
В следующем примере определяется тип перечисления с именем Выравниваниес базовым типом Int32.
enum Alignment
{
Left = -1,
Center = 0,
Right = 1
};
Как и для C++, перечисление MIDL 3.0 может содержать константное выражение, указывающее значение члена (как показано выше). Значение константы для каждого элемента перечисления должно находиться в диапазоне базового типа перечисления. Если объявление элемента перечисления явно не указывает значение, член получает нулевое значение (если это первый член в типе перечисления), или значение текстового элемента, предшествующего члену перечисления плюс один.
В следующем примере определяется тип перечисления с именем Permissionsс базовым типом UInt32.
[flags]
enum Permissions
{
None = 0x0000,
Camera = 0x0001,
Microphone = 0x0002
};
Типы, члены и другие сущности в исходном коде MIDL 3.0 поддерживают модификаторы, управляющие определенными аспектами их поведения. Например, специальные возможности метода контролируются с помощью модификатора доступа protected
. MIDL 3.0 обобщает эту возможность таким образом, что определяемые пользователем типы декларативной информации могут быть присоединены к сущностям программы и получены во время выполнения из метаданных.
Программы указывают эти дополнительные декларативные сведения путем определения и использования атрибутов .
В следующем примере определяется атрибут HelpAttribute, который можно поместить в сущности программы для предоставления ссылок на связанную документацию. Как видно, атрибут по сути является типом структуры, поэтому он не имеет конструктора и содержит только элементы данных.
[attributeusage(target_runtimeclass, target_event, target_method, target_property)]
attribute HelpAttribute
{
String ClassUri;
String MemberTopic;
}
Атрибут можно применить, указав его имя, а также любые аргументы внутри квадратных квадратных скобок непосредственно перед соответствующим объявлением. Если имя атрибута заканчивается атрибутом, то эта часть имени может быть опущена при ссылке на атрибут. Например, атрибут HelpAttribute можно использовать следующим образом.
[Help("https://docs.contoso.com/.../BookSku", "BookSku class")]
runtimeclass BookSku : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
[Help("https://docs.contoso.com/.../BookSku_Title", "Title method")]
String Title;
}
Один и тот же атрибут можно применить к нескольким объявлениям с помощью блока области после атрибута. То есть атрибут сразу же за ним следует фигурные скобки, окружающие объявления, к которым применяется атрибут.
runtimeclass Widget
{
[Help("https://docs.contoso.com/.../Widget", "Widget members")]
{
void Display(String text);
void Print();
Single Rate;
}
}
Атрибуты, реализованные как часть самого Windows, обычно находятся в пространстве имен Windows.Foundation.
Как показано в первом примере, вы используете атрибут [attributeusage(<target>)]
в определении атрибута. Допустимые целевые значения: target_all
, target_delegate
, target_enum
, target_event
, target_field
, target_interface
, target_method
, target_parameter
, target_property
, target_runtimeclass
и target_struct
. В круглые скобки можно включить несколько целевых объектов, разделенных запятыми.
Другие атрибуты, которые можно применить к атрибуту, являются [allowmultiple]
и [attributename("<name>")]
.
В приведенном ниже примере возникает ошибка MIDL2025: [msg]синтаксическая ошибка [контекст]: ожидание > или около ">>".
Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String>> RetrieveCollectionAsync();
Вместо этого вставьте пробел между двумя символами >
, чтобы пара закрывающих шаблонов символов не интерпретируется как оператор shift вправо.
Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String> > RetrieveCollectionAsync();
В приведенном ниже примере возникает ошибка MIDL2025: [msg]синтаксическая ошибка [контекст]: ожидание > или около "[". Это связано с недопустимым использование массива в качестве аргумента типа параметра в параметризованном интерфейсе.
Windows.Foundation.IAsyncOperation<Int32[]> RetrieveArrayAsync();
Сведения о решении см. в статье Возврат массива асинхронно.