Поделиться через


Предопределенные атрибуты (MIDL 3.0)

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

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

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

[allowforweb]Атрибут

Дополнительные сведения об использовании и назначении allowforweb атрибута см. в разделе класс алловфорвебаттрибуте.

[constructor_name]Атрибут

constructor_nameАтрибут задает имя и идентификатор IID интерфейса фабрики, содержащего элементы конструктора. Дополнительные сведения о интерфейсах фабрики см. в разделе синтезирование интерфейсов .

Примечание

Интерфейс фабрики применим только к запечатанному классу с конструкторами, отличными от конструктора по умолчанию, или к незапечатанному классу с конструкторами по умолчанию и (или) не по умолчанию.

В приведенном ниже примере защищенный конструктор блока размещается в интерфейсе иблоккфактори , а этот интерфейс имеет указанный IID.

[constructor_name("Windows.UI.Xaml.Documents.IBlockFactory", 07110532-4f59-4f3b-9ce5-25784c430507)]
...
unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    protected Block();
    ...
}

В результате, если в описании класса нет ссылки на интерфейс, но если он необходим для реализации класса, компилятор MIDL 3,0 создает и добавляет интерфейсы при необходимости.

[contentproperty]Атрибут

contentpropertyатрибут представляет класс атрибут ContentPropertyAttribute . Ниже приведен пример:

// BgLabelControl.idl
namespace BgLabelControlApp
{
    [contentproperty("Content")]
    runtimeclass BgLabelControl : Windows.UI.Xaml.Controls.Control
    {
        BgLabelControl();
        static Windows.UI.Xaml.DependencyProperty LabelProperty{ get; };
        String Label;
        static Windows.UI.Xaml.DependencyProperty ContentProperty{ get; };
        IInspectable Content;
    }
}

[contract]Атрибут

не используйте contract атрибут в собственных api-интерфейсах. он имеет только значение для встроенных Windows api.

contractатрибут задает имя и версию контракта API Windows 10 (см. раздел программирование с помощью пакетов sdk для расширений), в которых типизированный тип и (или) член впервые появился в Windows (поэтому он не имеет смысла для интерфейсов api, которые не доставляются как часть Windows). Атрибут принимает форму [contract(ContractName, ContractVersion)] и отображается перед элементом, к которому он применяется.

[default]Атрибут

Если не указать интерфейс по умолчанию, компилятор MIDL 3,0 выбирает первый интерфейс экземпляра. Чтобы переопределить этот выбор, вставьте default атрибут перед интерфейсом, который должен быть интерфейсом по умолчанию.

// Declaring an external interface as the default
runtimeclass C : [default]I { ... }

// Declaring a specific exclusiveto interface as the default.
// This is very unusual.
runtimeclass C
{
    ...

    [default][interface_name(...)]
    {
        ...
    }
}

[default_interface]Атрибут

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

[default_interface]
unsealed runtimeclass StateTriggerBase
{
    protected void SetActive(Boolean IsActive);
};

[default_overload]Атрибут

Примечание

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

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

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

runtimeclass Widget
{
    void Start();
    void Start(StartMode mode);
    void Start(StartMode mode, Widget parent);
}

В приведенном выше примере Start можно вызвать с двумя параметрами, чтобы указать режим запуска и родительское мини-приложение. Если не указать родительское мини-приложение, по умолчанию будет задано значение null. Если опустить режим, то он начнется в каком-то режиме по умолчанию для конкретного сценария.

В следующем примере мы используем девицеинформатион. креатеватчер .

runtimeclass DeviceInformation
{
    static DeviceWatcher CreateWatcher();
    static DeviceWatcher CreateWatcher(DeviceClass deviceClass);
    static DeviceWatcher CreateWatcher(String aqsFilter);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties,
                                       DeviceInformationKind kind);
}

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

Если вы решили использовать несколько перегрузок метода с одинаковым количеством параметров, возникает ошибка компилятора:

Перегрузки 1 параметра Девицеинформатион. Креатеватчер должны иметь ровно один метод, указанный в качестве перегрузки по умолчанию, добавив его в Windows. Foundation. Metadata. DefaultOverloadAttribute.

Причина, по которой некоторые языки программирования являются динамически типизированными. JavaScript и Python — это два примера. Для этих языков при выборе перегрузки учитывается только число параметров, а не их типы. Это означает, что вызов DeviceInformation.createWatcher(v); JavaScript является неоднозначным — v должен быть преобразован в девицеклассили в строку?

Чтобы устранить неоднозначность, необходимо применить [default_overload] атрибут к одному из методов. Но как выбрать нужный вариант?

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

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

Это делает метод девицекласс четким победителем. Так что вы указываете, что применяйте [default_overload] атрибут к этой перегрузке.

runtimeclass DeviceInformation
{
    static DeviceWatcher CreateWatcher();
    [default_overload]
    static DeviceWatcher CreateWatcher(DeviceClass deviceClass);
    static DeviceWatcher CreateWatcher(String aqsFilter);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties,
                                       DeviceInformationKind kind);
}

Что делать, если победитель не существует, так как все конфликтующие перегрузки предоставляют уникальные функции, недоступные из других перегрузок?

runtimeclass Widget
{
    static Widget Create(Uri source);
    static Widget Create(IInputStream source);
}

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

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

runtimeclass Widget
{
    static Widget CreateFromUri(Uri source);
    static Widget CreateFromStream(IInputStream source);
}

Теперь оба шаблона создания доступны для всех языков.

См. также перегрузку методов и проекция на основе классов.

[interface_name]Атрибут

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

В приведенном ниже примере атрибут, interface_name применяемый к RuntimeClass, указывает имя и идентификатор IID интерфейса, который содержит все члены экземпляра класса, которые в противном случае не были назначены интерфейсу. Таким образом, LineHeight, линестаккингстратеги, Marginи TextAlignment являются членами интерфейса иблокк .

Однако хоризонталтексталигнмент является членом интерфейса IBlock2 из-за interface_name атрибута, охватывающего этот элемент.

[interface_name("Windows.UI.Xaml.Documents.IBlock", 4bce0016-dd47-4350-8cb0-e171600ac896)]
...
unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    Double LineHeight;
    Windows.UI.Xaml.LineStackingStrategy LineStackingStrategy;
    Windows.UI.Xaml.Thickness Margin;
    Windows.UI.Xaml.TextAlignment TextAlignment;

    [interface_name("Windows.UI.Xaml.Documents.IBlock2", 5ec7bdf3-1333-4a92-8318-6caedc12ef89)]
    {
        Windows.UI.Xaml.TextAlignment HorizontalTextAlignment;
    }
    ...
}

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

[interface_name("Windows.UI.Xaml.IStateTriggerBase", 48b20698-af06-466c-8052-93666dde0e49)]
unsealed runtimeclass StateTriggerBase
{
    protected void SetActive(Boolean IsActive);
};

В результате, если в описании класса нет ссылки на интерфейс, но если он необходим для реализации класса, компилятор MIDL 3,0 создает и добавляет интерфейсы при необходимости.

Если вы используете default_interface необязательно, то MIDL 3,0 создает дополнительный пустой интерфейс и делает его по умолчанию.

[method_name]Атрибут

каждый интерфейс среда выполнения Windows имеет эквивалентный интерфейс в виде двоичного интерфейса приложения (ABI). Интерфейс ABI требует, чтобы все члены имели уникальные имена. Существует два варианта в MIDL 3,0, где члены не имеют имени или не имеют уникального имени.

  • конструкторы и
  • два или более перегруженных метода.

В этих случаях компилятор MIDL 3,0 при необходимости синтезирован уникальное имя элемента.

По умолчанию компилятор присваивает методам конструкторов имена <className> , <className> 2, <className> 3 и т. д. для эквивалентных методов в интерфейсе ABI. Иными словами, добавляется наименьшее значение неиспользуемого суффикса целочисленных чисел (начиная с 2), чтобы имя метода конструктора было уникальным.

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

Например, следующий IDL объявляет три перегрузки DoWorkи две перегрузки другого метода с именем DoWork3.

void DoWork(Int32 x);
void DoWork3(Int32 x);
void DoWork(Int32 x, Int32 y);
void DoWork(Int32 x, Int32 y, Int32 z);
void DoWork3(Int32 x, Int32 y);

По умолчанию (так как имя DoWork3 уже занято) компилятор передает три перегрузки DoWork имен

  • DoWork
  • DoWork2
  • DoWork4.

DoWork3не является перегрузкой DoWork . По умолчанию компилятор предоставляет две перегрузки DoWork3 имен

  • DoWork3
  • DoWork32.

В порядке vtable функции будут отображаться как

  • DoWork
  • DoWork3
  • DoWork2
  • DoWork4
  • DoWork32

Можно переопределить назначение имени компилятора по умолчанию с помощью method_name атрибута.

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

unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    [method_name("CreateInstance")] protected Block();
    ...
}

[static_name]Атрибут

static_nameАтрибут задает имя и идентификатор IID интерфейса, содержащего статические члены класса.

В следующем примере атрибут, static_name применяемый к RuntimeClass, указывает имя и идентификатор IID интерфейса, который содержит все статические члены класса, которые в противном случае не были назначены интерфейсу. Таким образом, линехеигхтпроперти, линестаккингстратегипроперти, маргинпропертии тексталигнментпроперти являются членами интерфейса IBlockStatics .

Однако хоризонталтексталигнментпроперти является членом интерфейса IBlockStatics2 из-за static_name атрибута, охватывающего этот элемент.

[static_name("Windows.UI.Xaml.Documents.IBlockStatics", f86a8c34-8d18-4c53-aebd-91e610a5e010)]
...
unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    static Windows.UI.Xaml.DependencyProperty LineHeightProperty{ get; };
    static Windows.UI.Xaml.DependencyProperty LineStackingStrategyProperty{ get; };
    static Windows.UI.Xaml.DependencyProperty MarginProperty{ get; };
    static Windows.UI.Xaml.DependencyProperty TextAlignmentProperty{ get; };

    [static_name("Windows.UI.Xaml.Documents.IBlockStatics2", af01a4d6-03e3-4cee-9b02-2bfc308b27a9)]
    {
        static Windows.UI.Xaml.DependencyProperty HorizontalTextAlignmentProperty{ get; };
    }
    ...
}