Vordefinierte Attribute (MIDL 3.0)

Es gibt eine Reihe vordefinierter benutzerdefinierter Attribute, mit denen Sie den Namen und den Schnittstellenbezeichner (IID) für compilersynthetisierte Schnittstellen steuern können. Mit diesen Attributen können Sie die Versions- und binäre API Ihrer Klasse auf einer differenzierten Ebene steuern.

Wenn Sie ein Komponentenentwickler und/oder Bibliotheksautor sind, können Sie diese Attribute verwenden, um sicherzustellen, dass Ihre Komponenten von einer Version zur nächsten binär stabil bleiben.

Wenn Sie ein Anwendungsentwickler sind, müssen Sie diese Attribute im Allgemeinen nicht verwenden, da Sie Ihre Anwendung nach der Revision Ihrer Typen neu kompilieren.

Das [allowforweb] Attribut

Ausführliche Informationen zur Verwendung und zum Zweck des allowforweb Attributs finden Sie in der AllowForWebAttribute-Klasse.

Das [constructor_name] Attribut

Das constructor_name -Attribut gibt den Namen und die IID der Factoryschnittstelle an, die die Konstruktormember enthält. Weitere Informationen zu Factoryschnittstellen finden Sie unter Synthesizing interfaces (Synthetisieren von Schnittstellen ).

Hinweis

Eine Factoryschnittstelle gilt nur für eine versiegelte Klasse mit nicht standardmäßigen Konstruktoren oder für eine nicht versiegelte Klasse mit Standardkonstruktoren und/oder nicht standardmäßigen Konstruktoren.

Im folgenden Beispiel wird der geschützte Blockkonstruktor in der IBlockFactory-Schnittstelle platziert, und diese Schnittstelle verfügt über die angegebene IID.

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

Wenn Ihre Klassenbeschreibung andernfalls nicht auf eine Schnittstelle verweist, aber zum Implementieren der Klasse erforderlich ist, synthetisiert der MIDL 3.0-Compiler nach Bedarf Schnittstellen und fügt sie hinzu.

Das [contentproperty] Attribut

das contentproperty -Attribut stellt die ContentPropertyAttribute-Klasse dar. Hier sehen Sie ein Beispiel:

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

Das [contract] Attribut

Verwenden Sie das contract -Attribut nicht in Ihren eigenen APIs, sondern nur für integrierte Windows-APIs.

Das contract -Attribut gibt den Namen und die Version des Windows 10-API-Vertrags an (siehe Programmierung mit Erweiterungs-SDKs), in dem der attributierte Typ und/oder Member zuerst in Windows eingeführt wurde (daher ist es für APIs, die nicht als Teil Windows bereitgestellt werden, nicht sinnvoll). Das Attribut hat das Format [contract(ContractName, ContractVersion)]und wird vor dem Element angezeigt, für das es gilt.

Das [default] Attribut

Wenn Sie keine Standardschnittstelle angeben, wählt der MIDL 3.0-Compiler die erste Instanzschnittstelle aus. Um diese Auswahl zu überschreiben, fügen Sie das - default Attribut vor der Schnittstelle ein, die Die Standardschnittstelle sein soll.

// 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(...)]
    {
        ...
    }
}

Das [default_interface] Attribut

Das default_interface -Attribut wird verwendet, um die Generierung einer Standardschnittstelle zu erzwingen, bei der andernfalls keine generiert wird. Im folgenden Beispiel ist für StateTriggerBase keine Standardschnittstelle erforderlich (da sie keine öffentlichen nicht statischen Member enthält), sodass nur das default_interface Vorhandensein des Attributs bewirkt, dass ein -Attribut (mit dem Namen IStateTriggerBase) generiert wird.

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

Das [default_overload] Attribut

Hinweis

Dieses Attribut wird für Konstruktoren nicht unterstützt. Wenn Sie Ihre Konstruktoren nicht nach Arity überladen können, können Sie überladene Factorymethoden wie die Beispiele CreateFromUri und CreateFromStream definieren, die im letzten Codeausschnitt in diesem Abschnitt gezeigt werden.

Das default_overload Attribut stellt die DefaultOverloadAttribute-Klasse dar, die angibt, dass eine Methode die Standardüberladungsmethode ist. In diesem Abschnitt werden die Gründe und Verwendungsrichtlinien für das [default_overload] -Attribut erläutert.

Sie können Windows-Runtime Methoden nach Arität frei überladen. Das heißt, Sie können mehrere Methoden mit dem gleichen Namen definieren, solange jede methode eine andere Anzahl von Argumenten verwendet. Aus Gründen der Benutzerfreundlichkeit empfiehlt es sich, am Ende neue Parameter hinzuzufügen und das Verhalten der Funktion "shorter-parameter-list" dem Aufrufen der Funktion "longer-parameter-list" mit (szenariospezifischen) natürlichen Standardwerten für die fehlenden Parameter zu entsprechen.

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

Im obigen Beispiel kann Start mit zwei Parametern aufgerufen werden, um einen Startmodus und ein übergeordnetes Widget anzugeben. Wenn Sie das übergeordnete Widget weglassen, wird standardmäßig NULL verwendet. Wenn Sie den Modus weglassen, wird er in einem szenariospezifischen Standardmodus gestartet.

In diesem nächsten Beispiel verwenden wir DeviceInformation.CreateWatcher .

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

In diesem Beispiel gibt es fünf Überladungen, und die meisten folgen dem empfohlenen Muster, dass jede neue Überladung eine Erweiterung der vorherigen Überladung ist.

Wenn Sie mehrere Überladungen einer Methode mit der gleichen Anzahl von Parametern verwenden möchten, erhalten Sie einen Compilerfehler:

Die 1-Parameter-Überladungen von DeviceInformation.CreateWatcher müssen genau eine Methode als Standardüberladung angegeben haben, indem sie mit Windows. Foundation.Metadata.DefaultOverloadAttribute.

Der Grund dafür ist, dass einige Programmiersprachen dynamisch typisiert sind. JavaScript und Python sind zwei Beispiele. Bei diesen Sprachen berücksichtigt die Auswahl der Überladung nur die Anzahl der Parameter und nicht deren Typen. Dies bedeutet, dass ein JavaScript-Aufruf von DeviceInformation.createWatcher(v); mehrdeutig ist– sollte v in eine DeviceClass oder eine Zeichenfolge geziert werden?

Um die Mehrdeutigkeit zu beheben, müssen Sie das [default_overload] -Attribut auf eine der -Methoden anwenden. Aber wie wählen Sie welche aus?

Sie sollten die Standardüberladung auswählen, damit die Funktionalität der nicht standardmäßigen Überladungen weiterhin auf andere Weise verfügbar ist, in der Regel durch eine der anderen Überladungen.

Im Beispiel DeviceInformation.CreateWatcher kann die Funktionalität der String-Überladung abgerufen werden, indem die Überladung String, IIterableString<> aufgerufen und eine leere Liste von Eigenschaften übergeben wird. Andererseits ist die DeviceClass-Überladung die einzige Möglichkeit, einen DeviceWatcher zu erstellen, der nach einer DeviceClass gefiltert wird.

Dadurch wird die DeviceClass-Methode zum eindeutigen Gewinner. Sie geben dies also an, indem Sie das [default_overload] -Attribut auf diese Überladung anwenden.

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

Was geschieht, wenn es keinen Gewinner gibt, da alle in Konflikt stehenden Überladungen eindeutige Funktionen bereitstellen, die von anderen Überladungen nicht verfügbar sind?

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

Unser hypothetisches Widgetobjekt kann aus einem URI oder aus einem Eingabestream erstellt werden. Wenn wir eine als Standardüberladung markieren, verlieren dynamisch typisierte Programmiersprachen vollständig den Zugriff auf die andere.

Um dieses Problem zu lösen, geben Sie den beiden Versionen unterschiedliche Namen, damit sie nicht überladen werden.

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

Jetzt sind beide Erstellungsmuster für alle Sprachen verfügbar.

Siehe auch Methodenüberladung und klassenbasierte Projektion.

Das [interface_name] Attribut

Das interface_name -Attribut gibt den Namen und die IID der Schnittstelle an, die die Instanzmember der -Klasse enthält. Standardmäßig weist der Compiler Schnittstellennamen mit demselben eindeutigen Nummerierungsalgorithmus zu, den er für Methoden verwendet.

Im folgenden Beispiel gibt das interface_name auf die Runtimeklasse angewendete Attribut den Namen und die IID der Schnittstelle an, die alle Instanzmember der -Klasse enthält, die andernfalls keiner Schnittstelle zugewiesen sind. LineHeight, LineStackingStrategy, Margin und TextAlignment sind also Member der IBlock-Schnittstelle.

HorizontalTextAlignment ist jedoch aufgrund des Attributs, das diesen Member umfasst, ein Member der interface_nameIBlock2-Schnittstelle.

[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;
    }
    ...
}

Sie können auch das interface_name -Attribut verwenden, um die Generierung einer Schnittstelle zu erzwingen. Im folgenden Beispiel benötigt StateTriggerBaseIStateTriggerBase nicht, und nur das interface_name Vorhandensein des Attributs bewirkt, dass es generiert wird.

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

Wenn Ihre Klassenbeschreibung andernfalls nicht auf eine Schnittstelle verweist, aber zum Implementieren der Klasse erforderlich ist, synthetisiert der MIDL 3.0-Compiler nach Bedarf Schnittstellen und fügt sie hinzu.

Wenn Sie unnötigerweise default_interface verwenden, generiert MIDL 3.0 eine zusätzliche leere Schnittstelle und legt diese als Standard fest.

Das [method_name] Attribut

Jede Windows-Runtime-Schnittstelle verfügt über eine entsprechende ABI-Schnittstelle (Application Binary Interface). Die ABI-Schnittstelle erfordert, dass alle Member eindeutige Namen haben. Es gibt zwei Fälle in MIDL 3.0, in denen Member entweder keinen Namen oder keinen eindeutigen Namen haben.

  • -Konstruktoren und
  • zwei oder mehr überladene Methoden.

In diesen Fällen synthetisiert der MIDL 3.0-Compiler nach Bedarf einen eindeutigen Membernamen.

Standardmäßig weist der Compiler Konstruktormethoden die Namen <className>, <className2>, <className3> usw. für die entsprechenden Methoden in der ABI-Schnittstelle zu. Anders ausgedrückt: Das kleinste nicht verwendete ganzzahlige Zahlensuffix (von 2 heraufsteigend) wird hinzugefügt, um den Namen der Konstruktormethode eindeutig zu machen.

Ebenso verwendet der Compiler für überladene Methoden für die erste Methode in einer Reihe von Überladungen (in lexikalischer Reihenfolge) den ursprünglichen Methodennamen für die entsprechende ABI-Schnittstellenmethode. Nachfolgende Überladungen werden eindeutig, indem dem ursprünglichen Namen das kleinste nicht verwendete ganzzahlige Zahlensuffix hinzugefügt wird (von 2 heraufsteigend).

Die folgende IDL deklariert beispielsweise drei Überladungen von DoWork und zwei Überladungen einer anderen Methode namens 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);

Standardmäßig (da der Name DoWork3 bereits verwendet wird) weist der Compiler den drei Überladungen von DoWork die Namen zu.

  • Dowork
  • DoWork2
  • DoWork4.

DoWork3 ist keineDoWork-Überladung . Standardmäßig gibt der Compiler den beiden Überladungen von DoWork3 die Namen

  • DoWork3
  • DoWork32.

In der vtable-Reihenfolge werden die Funktionen als angezeigt.

  • Dowork
  • DoWork3
  • DoWork2
  • DoWork4
  • DoWork32

Sie können die Standardnamenzuweisung des Compilers mithilfe des method_name -Attributs überschreiben.

Im nächsten Beispiel weisen wir den Compiler an, den Namen CreateInstance für den Block-Standardkonstruktormember zu verwenden.

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

Das [static_name] Attribut

Das static_name -Attribut gibt den Namen und die IID der Schnittstelle an, die statische Member der -Klasse enthält.

In diesem nächsten Beispiel gibt das static_name auf die Runtimeklasse angewendete Attribut den Namen und die IID der Schnittstelle an, die alle statischen Member der Klasse enthält, die andernfalls keiner Schnittstelle zugewiesen sind. LineHeightProperty, LineStackingStrategyProperty, MarginProperty und TextAlignmentProperty sind also Member der IBlockStatics-Schnittstelle.

HorizontalTextAlignmentProperty ist jedoch aufgrund des Attributs, das diesen Member umfasst, ein Member der static_nameIBlockStatics2-Schnittstelle.

[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; };
    }
    ...
}