Вводные сведения о языке MIDL 3.0.

Язык определения интерфейса Майкрософт (MIDL) 3.0 — это упрощенный современный синтаксис для определения среда выполнения Windows типов в файлах (IDL.idl). Этот новый синтаксис будет знаком любому, кто сталкивается с C, C++, C# и (или) Java. MIDL 3.0 — это особенно удобный способ определения классов среды выполнения C++/WinRT , что значительно более кратким, чем предыдущие версии IDL (сокращение макетов на две трети по длине и использование разумных значений по умолчанию для уменьшения необходимости декорирования атрибутами).

Вот как выглядит 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).

MIDL 1.0, 2.0 и 3.0

Язык определения интерфейса (IDL) начался с системы распределенных вычислений или удаленных вызовов процедур (DCE/RPC). Исходный MIDL 1.0 — DCE/RPC IDL с усовершенствованиями для определения com-интерфейсов и коклассов.

Затем в корпорации Майкрософт был разработан обновленный синтаксис MIDL 2.0 (также известный как MIDLRT) для объявления среда выполнения Windows API для платформы Windows. Если вы посмотрите в папку %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\winrt Windows SDK, вы увидите примеры файлов, написанных .idl с помощью синтаксиса MIDL 2.0. Это встроенные среда выполнения Windows API, объявленные в форме двоичного интерфейса приложения (ABI). Эти файлы существуют в первую очередь для использования инструментов— вы не будете создавать и использовать эти API в этой форме (если вы не пишете очень низкоуровневый код).

См. также переход на MIDL 3.0 с классической версии MIDLRT.

MIDL 3.0 — это гораздо более простой и более современный синтаксис, цель которого — объявить среда выполнения Windows API. И его можно использовать в проектах, особенно для определения классов среды выполнения C++/WinRT . Заголовки для использования из C++/WinRT для встроенных API-интерфейсов среда выполнения Windows являются частью пакета SDK в папке%WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt.

Варианты использования ДЛЯ MIDL 3.0

Как правило, все api-интерфейсы среда выполнения Windows предназначены для всех среда выполнения Windows языковых проекций. Это делается, отчасти, выбирая исключительно передавать среда выполнения Windows типы в СРЕДА ВЫПОЛНЕНИЯ WINDOWS API и из нее. Хотя это допустимое решение по проектированию для передачи необработанного 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 C++ (WRC), который напрямую создает и использует COM-компонент (например, DirectX) и предоставляет репликацию некоторых подмножеств его функций и функций в форма поверхности API среда выполнения Windows, которая принимает и возвращает только среда выполнения Windows типы. Затем можно использовать этот WRC из приложения, написанного в любой среда выполнения Windows проекции языка.

Структура определения и вызов midl.exe из командной строки

Ключевыми понятиями организации в определении 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) и два метода с именами Equals и ApplyDiscount. Обратите внимание на использование типа Single , а не float. И эта строка имеет верхний регистр "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-файлов (для получения рекомендаций об этом, ознакомьтесь с классами среды выполнения факторинга в файлы Midl (IDL)), то объедините все полученные .winmd файлы в один файл с тем же именем, что и корневое пространство имен. .winmd Последний файл будет тем, на который будут ссылаться потребители API.

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

Кстати, можно использовать where команду, чтобы узнать, где midl.exe установлена установка.

where midl

Если вы хотите использовать типы, определенные в одном .idl файле из другого .idl файла, используйте директиву import . Дополнительные сведения и пример кода см. в элементах управления XAML; привязке к свойству C++/WinRT. Конечно, если вы используете встроенный или сторонний компонент, у вас не будет доступа к файлу .idl . Например, может потребоваться использовать API Win2D среда выполнения Windows для отрисовки графики в режиме немедленного режима. Приведенная выше команда использовала /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
Boolean: Boolean
128-разрядный UUID: Guid
Типы перечисления Определяемые пользователем типы перечисления формы E {...}
Типы структур Определяемые пользователем типы структуры формы S {...}
Типы, допускающие значение NULL Расширения всех остальных типов значений со значением NULL
Ссылочные типы Типы классов Конечный базовый класс всех других типов: Object
Определяемые пользователем типы класса среды выполнения формы 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.

Категория Bits Тип Диапазон и точность
Целочисленный со знаком 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 Single От 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 типа T (за исключением String) существует соответствующий тип, допускающий значение NULL Windows.Foundation.IReference<T>, который может содержать дополнительное значение null. Например, Windows.Foundation.IReference<Int32> — это тип, который может содержать любое 32-разрядное целое число или значение null. Также см. IReference<T>.

Наконец, MIDL 3.0 поддерживает тип объекта, который сопоставляется с интерфейсом среда выполнения Windows IInspectable. Ссылочные типы интерфейса и runtimeclass концептуально являются производными от типа объекта ; делегат не имеет.

Выражения в перечислимом значении

При использовании 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 Вычитание, удаление делегатов
Shift x << y Сдвиг влево
x >> y Сдвиг вправо
Побитовое И x & y Побитовое целое число И
Побитовое исключающее ИЛИ 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, где некоторые разделяемые классы создаются машинным образом.

Модификатор Значение
static Класс не имеет экземпляров. Следовательно, разрешены только статические члены.
partial Определение класса является неполным.

Дополнительные модификаторы см. в разделе "Композиция и активация ".

Модификаторы доступа к членам

Поскольку MIDL 3.0 является языком определения для описания общедоступной поверхности среда выполнения Windows типов, нет необходимости явного синтаксиса объявлять общедоступную доступность члена. Все члены неявно открыты. Поэтому MIDL 3.0 не требует и не разрешает (эффективно избыточное) public ключевое слово.

базовых классов;

Определение класса может указывать базовый класс, следуя параметрам имени класса и типа с двоеточием и именем базового класса. Пропуск спецификации базового класса совпадает с производным от типа Object (другими словами, от IInspectable).

Примечание

Классы модели представления ( фактически, любой класс среды выполнения, который вы определяете в приложении), не должны быть производными от базового класса.

Любой класс среды выполнения, который определяется в приложении, который является производным от базового класса, называется составным классом . На составные классы накладываются определенные ограничения. Чтобы приложение прошло тесты комплекта сертификации приложений для Windows, используемые Visual Studio и Microsoft Store для проверки отправляемого кода (и, следовательно, чтобы оно было успешно принято в Microsoft Store), составляемый класс в конечном счете должен быть производным от базового класса Windows. Это означает, что класс с самого корня иерархии наследования должен иметь тип, полученный в пространстве имен Windows.*.

Дополнительные сведения см. в статье Элементы управления XAML; привязка к свойству C++/WinRT.

В следующем примере базовый класс VolumeArea, а базовым классом 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).

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

В предыдущем примере том наследует свойства Height и Width из Области. Таким образом, каждый экземпляр тома содержит три свойства: Height, Width и Depth.

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

Реализованные интерфейсы

Определение класса также может указывать список интерфейсов, которые реализует класс. Интерфейсы указываются в виде разделенного запятыми списка интерфейсов после базового класса (необязательно).

В приведенном ниже примере класс Area реализует интерфейс IStringable ; и класс Volume реализует интерфейс IStringable и гипотетический интерфейс IEquatable .

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 поддерживает объявление конструкторов экземпляров. Конструктор экземпляра — это метод, реализующий действия, необходимые для инициализации экземпляра класса. Конструкторы не могут быть статическими.

Конструктор объявляется как метод экземпляра (но без возвращаемого типа) и с тем же именем, что и содержащий класс.

Конструкторы экземпляров могут быть перегружены. Например, приведенный ниже класс Test объявляет три конструктора экземпляра; один без параметров (конструктор по умолчанию ), тот, который принимает параметр Int32 , и тот, который принимает два двойных параметра (параметризованные конструкторы).

runtimeclass Test
{
    Test();
    Test(Int32 x);
    Test(Double x, Double y);
}

Дополнительные сведения о синтаксисе списков параметров см. в разделе "Методы " ниже.

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

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

Свойства

Свойства концептуально похожи на поля (например, C# поля; или поля структуры MIDL 3.0). Свойства и поля являются элементами с именем и связанным типом. Однако свойства, в отличие от полей, не указывают места хранения. Вместо этого свойства имеют методы доступа , указывающие функцию, выполняемую при чтении или записи свойства.

Свойство объявляется как поле структуры, за исключением того, что объявление заканчивается ключевым словом get и /или set ключевым словом, написанным между разделителями { и }, и заканчивая точкой с запятой.

Свойство с ключевым словом get и set ключевым словом является свойством чтения и записи. Свойство, которое имеет только ключевое get слово, является свойством только для чтения. Среда выполнения Windows не поддерживает свойства только для записи.

Например, область класса, показанная ранее, содержит два свойства чтения и записи с именем Height и Width.

unsealed runtimeclass Area
{
    Int32 Height { get; set; };
    Int32 Width; // get and set are implied if both are omitted.
}

Объявление Width пропускает фигурные скобки и getset ключевые слова. Упущение подразумевает, что свойство доступно для чтения и записи и семантически идентично предоставлению get ключевых слов в этом порядкеget, за которым следуетsetset.

Кроме того, можно указать только ключевое 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 для чтения и записи, и вам не нужно поддерживать двоичную совместимость с предыдущими определениями Area (например, класс Area является типом в приложении, которое вы повторно компилируете каждый раз), то можно просто добавить set ключевое слово в существующее объявление SurfaceColor , как показано ниже.

unsealed runtimeclass Area
{
    ...
    Color SurfaceColor { get; set; };
}

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

В этом случае добавьте ключевое слово свойства set в дополнительное определение свойства в конце класса, как показано ниже.

unsealed runtimeclass Area
{
    ...
    Color SurfaceColor { get; };
    ...
    Color SurfaceColor { set; };
}

Компилятор создает ошибку для свойства только для записи. Но это не то, что делается здесь. Из-за предыдущего объявления свойства как доступного только для чтения, добавление ключевого слова set не объявляет свойство только для записи, а свойство read-write.

Реализация свойства среда выполнения Windows является одним или двумя методами доступа в интерфейсе. Порядок ключевых слов get и set в объявлении свойства определяет порядок методов get и set accessor в интерфейсе резервного копирования.

Метод 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. Это связано с тем, что слаботипизированные языки программирования не поддерживают перегрузку по типу.

Параметры

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

Параметры метода получают их значение из определенного аргумента , указанного при вызове метода. Способ передача аргументов между вызывающим и вызываемого объекта зависит от типа параметра. По умолчанию все параметры являются входными параметрами, то есть маршалируются от вызывающего объекта только вызывающей стороны. Ключевые слова-модификаторыrefref const, и out их можно добавить для изменения направления маршалинга по умолчанию между вызывающим и вызывающим абонентом, а также для создания выходных параметров. Однако не все ключевые слова допустимы со всеми типами параметров; Допустимые сочетания подробно описаны ниже.

Важно!

Среда CLR содержит основные понятия и ключевые слова-модификаторы, которые могут быть похожи на те, которые описаны в этом разделе. Однако на практике они не связаны, и влияние этих модификаторов зависит от проектирования и функционирования среда выполнения Windows.

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

runtimeclass Test
{
    static void Divide(Int32 x, Int32 y, out Int32 result, out Int32 remainder);
}

В качестве специальной оптимизации производительности типы структур (и другие типы), которые обычно передаются по значению в виде полной копии, могут быть переданы указателем на неизменяемую структуру. Это достигается с ref const помощью ключевого слова (notconst 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);
}

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

Поведение Выделено Ключевое слово Типы Комментарии
Входной параметр Caller (нет) Все типы Поведение по умолчанию
ref const Только структуры Оптимизация производительности
Выходной параметр Вызываемая функция out Все типы

среда выполнения Windows поддерживает типы массивов, поведение которых в качестве параметра несколько отличается. Массив — это структура данных, содержащая ряд переменных, хранящихся последовательно и доступ к которым осуществляется через индекс. Переменные, содержащиеся в массиве, также называемые элементами массива, имеют одинаковый тип, и этот тип называется типом элемента массива.

MIDL 3.0 поддерживает объявления одномерного массива.

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

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" (Передача массива) (нет) Caller Только для чтения
"Массив заливки" ref Caller Только на запись
"Массив получения" out Вызываемая функция Чтение и запись

Дополнительные сведения об использовании параметров массива в стиле C ( также известных как соответствующие массивы) с C++/WinRT см. в разделе "Параметры массива".

Статические методы и методы экземпляра

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

Метод, объявленный с модификатором static, является методом экземпляра. Метод экземпляра имеет доступ к конкретному экземпляру и может получить доступ как к статическим, так и к членам экземпляра класса.

Следующий класс Entity имеет как статические, так и члены экземпляра.

runtimeclass Entity
{
    Int32 SerialNo { get; };
    static Int32 GetNextSerialNo();
    static void SetNextSerialNo(Int32 value);
}

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

Свойство SerialNo предоставляет доступ к серийному номеру для экземпляра, на котором вызывается метод get свойства .

Статические методы GetNextSerialNo и SetNextSerialNo могут получить доступ к внутреннему следующему доступного статического члена классаEntity .

Переопределимые и защищенные методы

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

Метод можно переопределить в производном классе. Если объявление метода экземпляра содержит overridable модификатор, метод может быть переопределен производными классами. Определяется ли производный класс фактически переопределением переопределенного метода базового класса. Он отсутствует в метаданных. Если производный класс повторно объявляет метод в базовом классе, он объявляет новый метод, который находится рядом с производным методом класса, а не переопределяет его.

Если объявление метода экземпляра содержит protected модификатор, метод виден только производным классам.

События

Объявление события — это член, указывающий, что класс является источником событий. Такой источник событий предоставляет уведомления любому получателю, реализующим делегат (метод с определенной сигнатурой).

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

runtimeclass Area
{
    ...
    event Windows.UI.Xaml.WindowSizeChangedEventHandler SizeChanged;
    ...
}

Объявление события неявно добавляет в класс два метода: метод add , который клиент вызывает для добавления обработчика событий в источник, и метод remove, который клиент вызывает для удаления ранее добавленного обработчика событий. Ниже приведены дополнительные примеры.

// 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. Это может привести к беспорядочному дизайну, особенно при учете управления версиями.

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

Тип перечисления (или перечислимый тип или перечисление) — это отдельный тип значения с набором именованных констант. В следующем примере определяется и используется тип перечисления с именем Color с тремя константными значениями: Red, Green и Blue.

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,
};

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

В следующем примере определяется тип перечисления с именем Alignment с базовым типом Int32.

enum Alignment
{
    Left = -1,
    Center = 0,
    Right = 1
};

Как и для C и 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_fieldtarget_interfacetarget_delegatetarget_parametertarget_methodtarget_enumtarget_event, target_propertyи . target_runtimeclasstarget_struct В круглые скобки можно включить несколько целевых объектов, разделенных запятыми.

Другие атрибуты, которые можно применить к атрибуту, и [allowmultiple][attributename("<name>")].

Параметризованный тип

В приведенном ниже примере возникает ошибка MIDL2025: [msg]синтаксическая ошибка [контекст]: ожидание > или почти ">>".

Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String>> RetrieveCollectionAsync();

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

Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVector<String> > RetrieveCollectionAsync();

В приведенном ниже примере возникает ошибка MIDL2025: [msg]синтаксическая ошибка [контекст]: ожидание > или около "[". Это связано с тем, что недопустимо использовать массив в качестве аргумента типа параметра для параметризованного интерфейса.

Windows.Foundation.IAsyncOperation<Int32[]> RetrieveArrayAsync();

Сведения о решении см. в разделе "Возврат массива асинхронно".