Sistema di tipi Windows Runtime (WinRT)

Note generali

Tutti i tipi, ad eccezione dei tipi fondamentali, devono essere contenuti all'interno di uno spazio dei nomi. Non è valido per un tipo nello spazio dei nomi globale.

I tipi forniti da Windows sono tutti contenuti nello spazio dei nomi Windows.*. I tipi WinRT non forniti da Windows (inclusi i tipi WinRT forniti da altre parti di Microsoft) devono risiedere in uno spazio dei nomi diverso da Windows.*.

Ad eccezione delle interfacce, tutti i tipi WinRT devono avere visibilità pubblica. Le interfacce WinRT possono facoltativamente avere visibilità privata. Tutti gli altri tipi WinRT definiti dall'utente (struct, classi, enumerazioni, delegati, attributi) devono avere visibilità pubblica.

WinRT non supporta i tipi annidati. Nessun tipo WinRT può racchiudere un altro tipo; nessun tipo WinRT può essere annidato all'interno di un altro tipo.

Non tutti gli aspetti del sistema di tipi WinRT sono disponibili per te, come sviluppatore di terze parti.

  • WinRT supporta la parametrizzazione di interfacce e delegati. Tuttavia, in questa versione WinRT non supporta la definizione di tipi con parametri da parte di terze parti. Sono supportati solo i tipi con parametri inclusi nel sistema nello spazio dei nomi Windows.*.

  • WinRT supporta la composizione della classe come meccanismo di ereditarietà di runtime. Tuttavia, in questa versione WinRT non supporta la definizione di una classe componibile radice. Sono supportate solo le classi componibili radice incluse nel sistema nello spazio dei nomi Windows.*.

Gli spazi dei nomi e i nomi dei tipi WinRT conservano la distinzione tra maiuscole e minuscole, ma non fanno distinzione tra maiuscole e minuscole, in modo analogo al file system Windows e al Registro di sistema Windows. Ciò significa che non è possibile avere spazi dei nomi o nomi di tipi che variano solo in base al caso. Ad esempio, non è possibile avere sia Foo.SomeType che foo. AnotherType, né è possibile avere sia Foo.SomeType che Foo.someType.

Un identificatore WinRT deve essere conforme alla grammatica seguente. Si noti che sono supportati solo i caratteri definiti in Unicode 3.0 e versioni precedenti.

    identifier-or-keyword: 
        identifier-start-character   identifier-continuation-characters* 
    identifier-start-character: 
        letter-character
        underscore (U+005F) 
    identifier-continuation-characters: 
        identifier-continuation-character
        identifier-continuation-characters   identifier-continuation-character 
    identifier-continuation-character: 
        identifier-start-character 
        decimal-digit-character
        connecting-character
        combining-character
        formatting-character 
    letter-character: 
        A Unicode 3.0 character of classes Lu, Ll, Lt, Lm, Lo, or Nl 
    combining-character: 
        A Unicode 3.0 character of classes Mn or Mc 
    decimal-digit-character: 
        A Unicode 3.0 character of the class Nd 
    connecting-character: 
        A Unicode 3.0 character of the class Pc 
    formatting-character: 
        Zero Width Non-Joiner (U+200C)
        Zero Width Joiner (U+200D)

Tipi con parametri

WinRT supporta la parametrizzazione dei tipi di interfacce e delegati. I tipi con parametri consentono di definire una famiglia di interfacce che possono essere elaborate polimorficamente nei linguaggi di programmazione che supportano il polimorfismo parametrico.

Un'istanza del tipo con parametri si verifica quando viene specificata un'istanza di un tipo con parametri con un elenco di argomenti di tipi in un contesto di tipo, ad esempio una posizione del parametro del metodo. Ad esempio, HRESULT foo(X<Y> x) crea un'istanza del tipo con parametri denominato da X con il tipo Y come primo e solo argomento di tipo.

A un'interfaccia o a un delegato WinRT senza parametri viene assegnato un GUID per identificare in modo univoco l'interfaccia sottostante come distinta da altre interfacce nello stesso oggetto. A un'interfaccia con parametri (ad esempio, IVector<T>) o delegato (ad esempio, EventHandler<T>) viene assegnato un ID di interfaccia con parametri (PIID), che è un GUID che identifica in modo univoco questo tipo con parametri. Questo non è un IID. Questo GUID viene usato per generare ID di tipi con parametri per le istanze di tipo con parametri ( ad esempio , IVector<int>).

Elenco di argomenti di tipo con parametri

Questi tipi WinRT possono essere visualizzati nell'elenco di argomenti per un tipo con parametri.

  • Tipi fondamentali winRT (ad esempio, Boolean, Int32, String, Guid e così via)
  • Enumerazioni WinRT
  • Struct WinRT
  • Interfacce WinRT
  • Delegati WinRT
  • Classi di runtime WinRT
  • Altre istanze di tipo con parametri ( ad esempio IVector<IVector<int>>) Qualsiasi altro tipo non può essere visualizzato in un elenco di argomenti di tipo con parametri. Ad esempio, matrici.

Istanze del tipo con parametri

Un'istanza del tipo con parametri può essere visualizzata in qualsiasi contesto in cui può essere visualizzato un tipo non con parametri. È possibile usare un'istanza dell'interfaccia con parametri in qualsiasi punto in cui è possibile usare un'interfaccia, ad esempio nell'elenco delle interfacce implementate da una classe di runtime. È possibile usare un'istanza del delegato con parametri in qualsiasi punto in cui può essere usato un delegato, ad esempio nella definizione di un evento.

È possibile visualizzare un parametro di tipo con parametri: nell'interfaccia con parametri o nella definizione del delegato; o, qualsiasi posizione che un tipo normale può normalmente apparire. Se viene visualizzato un parametro in cui è possibile visualizzare solo un'interfaccia, tale parametro è limitato a essere un'interfaccia. Se un parametro viene visualizzato in un contesto in cui è possibile visualizzare qualsiasi tipo, tale parametro non è limitato; e così via. Gli argomenti per le istanze di tipo con parametri devono soddisfare tutte queste restrizioni.

Generazione guid per i tipi con parametri

L'algoritmo di generazione guid deve soddisfare questi requisiti.

  • Quando viene creata un'istanza di un tipo con parametri due volte con gli stessi argomenti, entrambe le istanze devono essere assegnate allo stesso corpo di interfaccia o delegato e allo stesso IID.
  • Se vengono create istanze di due tipi con parametri diversi, anche con gli stessi argomenti, deve essere statisticamente improbabile che vengano assegnati lo stesso IID.
  • Se viene creata un'istanza di un tipo con parametri due volte, ma con argomenti diversi, è statisticamente improbabile che alle due istanze venga assegnato lo stesso IID.

Nota

Non è consentito creare un'istanza di un tipo con parametri con la stessa istanza di un argomento o come argomento di qualsiasi altro tipo con parametri visualizzato nell'elenco di argomenti, ovvero la creazione di istanze circolari. Ad esempio, se X = Foo<Y>, e Y = Foo<X>, la non circolarità è stata violata. Tuttavia, se X = Foo<Y> e Y = Foo<int>, la non circolarità è stata mantenuta.

L'algoritmo di creazione di istanze è il seguente.

  1. A ogni tipo con parametri viene assegnato un ID di interfaccia con parametri dall'autore, abbreviato PIID. Si noti che un PIID non è un ID ID, né viene passato come argomento a QueryInterface. L'autore deve assicurarsi che il PIID sia univoco per il tipo con parametri.
  2. La firma del tipo per un tipo di base è una stringa ottetto ASCII (vedere la tabella seguente). Ad esempio, Int32 è "i4".
  3. La firma del tipo per un'interfaccia che non è un'istanza di interfaccia con parametri è il relativo IID codificato in ASCII in forma tratteggiata e delimitato da parentesi graffe. Ad esempio, "{00000000-0000-0000-0000-000000000000}".
  4. La firma del tipo per un delegato che non è un'istanza del delegato con parametri è la stringa "delegate" e quindi l'IID come con le interfacce. Verrà visualizzata la grammatica dettagliata.
  5. Il GUID per un tipo con parametri viene calcolato in base a questa grammatica.
    • in base a UUID rfc 4122, calcolare l'hash generato da ver 5 sha-1 di signature_octets, che usa un singolo guid winrt pinterface/pintergroup come spazio dei nomi, come descritto in rfc 4122/4.3 e la firma del pinterface/pintergroup e gli argomenti di cui viene creata un'istanza con come stringa di nome.
    • alla creazione di un'istanza di pinterface viene assegnato questo GUID e alla firma da 4.
    signature_octets => guid_to_octets(wrt_pinterface_namespace) string_to_utf8_octets(ptype_instance_signature)

        wrt_pinterface_namespace => "11f47ad5-7b73-42c0-abae-878b1e16adee"

        ptype_instance_signature => pinterface_instance_signature | pdelegate_instance_ signature

        pinterface_instance _signature => "pinterface(" piid_guid  ";" args ")"

        pdelegate_instance _signature => "pinterface(" piid_guid ";" args ")"

        piid_guid => guid

        args => arg | arg ";" args

        arg => type_signature

        type_signature => base_type_identifer | com_interface_signature | interface _signature | delegate_signature  | interface_group_signature | runtime_class_signature | struct_signature | enum_signature | pinterface_instance_signature | pdelegate_instance_signature
        com_interface_signature => "cinterface(IInspectable)"

        base_type_identifier is defined below

        interface_signature => guid

        interface_group_signature => "ig(" interface_group_name ";" default_interface ")"

        runtime_class_signature => "rc(" runtime_class_name ";" default_interface ")"

        default_interface => type_signature

        struct_signature => "struct(" struct_name ";" args ")"

        enum_signature => "enum(" enum_name ";" enum_underlying_type ")"

        enum_underlying_type => type_signature

        delegate_signature => "delegate(" guid ")"

        guid => "{" dashed_hex "}"

        dashed_hex is the format that uuidgen writes in when passed no arguments.

            dashed_hex => hex{8} "-" hex{4} "-" hex{4} "-" hex{4} "-" hex{12}

            hex => [0-9a-f]
  1. Quando una creazione di istanze p-type viene passata come argomento a un'interfaccia pinterface, la firma calcolata al passaggio 3 viene usata come firma del tipo nell'elemento grammaticale 'pinterface_instance_signature' o 'pdelegate_instance_signature', a seconda delle esigenze.

Questi nomi vengono usati per i tipi di base quando vengono visualizzati.

  • UInt8 esegue il mapping a "u1"
  • Int32 esegue il mapping a "i4"
  • UInt32 esegue il mapping a "u4"
  • Int64 esegue il mapping a "i8"
  • UInt64 esegue il mapping a "u8"
  • Mapping singolo a "f4"
  • Doppio mapping a "f8"
  • Il valore booleano è mappato a "b1"
    • Si noti che, per ottenere il supporto dei parametri di tipo booleano , è necessario aggiungere /Yc:wchar_t per abilitare wchar_t come tipo predefinito.
  • Char16 esegue il mapping a "c2"
  • La stringa esegue il mapping a "string"
  • Guid esegue il mapping a "g16"

I nomi precedenti fanno distinzione tra maiuscole e minuscole. Ad eccezione di String, il nome del tipo usa un singolo carattere per suggerire il tipo di dati, seguito dalle dimensioni in byte. Questi nomi sono stati scelti: per essere concisi (per evitare grandi dimensioni nelle firme dei tipi di struct); per non apparire confusamente simile al nome WinRT, al nome RIDL, né al nome della proiezione del linguaggio per qualsiasi tipo; e ancora per rimanere approssimativamente leggibile dall'uomo.

Per enum_type_signature, l'unico valore 'underlying_type' valido è quello di Int32 o UInt32.

Per struct_type_signature, args è un elenco in ordine di type_signatures per i campi dello struct. Questi possono essere tipi di base o altri tipi di struct.

Struct_name e enum_name sono qualificati per lo spazio dei nomi, usando il punto "." come delimitatori. Ad esempio, "namespace X { struct A{ int; }; }" diventa "struct(X.A;i4)".

Default_interface deve essere l'istanza dell'interfaccia, l'istanza p-interface, il delegato o l'istanza p-delegate specificata come predefinita nella classe di runtime o nel corpo del gruppo di interfacce, usando l'attributo IDL '[default]'.

Si noti che gli attributi personalizzati vengono ignorati; si presume che non abbia alcun effetto sul marshalling.

Controllo delle versioni

Tutti i tipi WinRT, ad eccezione dei tipi fondamentali, devono avere un attributo Version. Le proiezioni del linguaggio usano le informazioni sull'attributo Version per abilitare la compatibilità con le versioni precedenti e per gli scenari di attivazione. I tipi di terze parti devono includere un attributo Version, ma devono essere ignorati dalle proiezioni del linguaggio. I componenti WinRT di terze parti sono inclusi esclusivamente nell'app, quindi non possono mai modificare la versione indipendentemente dall'app stessa.

L'attributo Version può essere applicato facoltativamente ai membri dell'interfaccia (metodi, proprietà ed eventi). Questa funzionalità è destinata alla creazione di classi di alto livello in C#/VB e C++/CX. Gli attributi della versione nei membri dell'interfaccia, anche Windows membri dell'interfaccia di sistema, devono essere ignorati in fase di esecuzione dalle proiezioni del linguaggio.

L'attributo Version include un parametro del costruttore integer senza segno a 32 bit. Per Windows tipi WinRT, questo valore è il valore NTDDI per la versione di Windows il costrutto di tipo associato è stato definito per la prima volta in . Per i tipi di terze parti, il significato di questo valore è l'autore del tipo.

Windows gli struct di sistema, i delegati e le interfacce non sono modificabili dopo la definizione. Non possono mai essere modificati in alcuna versione Windows successiva.

Windows le enumerazioni di sistema e le classi di runtime sono disponibili in modo aggiuntivo per la versione. Le enumerazioni possono aggiungere nuovi valori di enumerazione nelle versioni successive Windows. Le classi possono aggiungere nuove interfacce implementate (incluse le interfacce statiche, factory di attivazione, factory di composizione, sottoponibili a override e protette) nelle versioni Windows successive. Altre informazioni sul controllo delle versioni aggiuntive sono incluse nelle sezioni per le enumerazioni e le classi di runtime.

Spazi dei nomi

Uno spazio dei nomi è un ambito di denominazione usato per organizzare il codice ed evitare conflitti di denominazione. Tutti i tipi denominati nel sistema di tipi WinRT (enumerazioni, struct, delegati, interfacce e classi di runtime) risiedono in uno spazio dei nomi. Uno spazio dei nomi può contenere altri spazi dei nomi.

Tipi fondamentali

Il sistema Di tipo WinRT include un set di base di tipi primitivi predefiniti.

Tipo WinRT Descrizione del tipo
Int16 intero con segno a 16 bit
Int32 intero con segno a 32 bit
Int64 intero con segno a 64 bit
UInt8 intero senza segno a 8 bit
UInt16 intero senza segno a 16 bit
UInt32 intero senza segno a 32 bit
UInt64 intero senza segno a 64 bit
Single numero a virgola mobile IEEE 754 a 32 bit
Double numero a virgola mobile IEEE 754 a 64 bit
Char16 valore non numerico a 16 bit che rappresenta un'unità di codice UTF-16
Boolean valore booleano a 8 bit
string sequenza non modificabile di Char16 utilizzata per rappresentare il testo
Guid Guid standard a 128 bit

Enumerazioni

Un tipo enum è un tipo valore distinto con un set di costanti denominate.

Ogni tipo enum ha un tipo integrale corrispondente denominato tipo sottostante del tipo enum. Gli unici tipi sottostanti di enumerazione legale in WinRT sono Int32 e UInt32.

Un'enumerazione con un tipo sottostante di UInt32 deve contenere FlagsAttribute. Un'enumerazione con un tipo sottostante di Int32 non deve contenere FlagsAttribute.

Un'enumerazione deve avere visibilità pubblica.

Controllo delle versioni delle enumerazioni

Un'enumerazione è modificabile in modo aggiuntivo. Le versioni successive di una determinata enumerazione possono aggiungere valori (noti anche come costanti denominate). I valori preesistenti non possono essere rimossi o modificati. I valori di enumerazione contengono facoltativamente VersionAttribute per distinguere quando sono stati aggiunti valori specifici al tipo di enumerazione. I valori di enumerazione senza VersionAttribute sono considerati con lo stesso valore di versione del tipo di enumerazione che lo racchiude.

Struct

Uno struct è un tipo di record con uno o più campi. Gli struct vengono sempre passati e restituiti per valore. I campi Struct possono essere solo primitive, enumerazioni, struct, stringhe e IReference<T> (gli ultimi due sono i soli due tipi di campo allocati dall'heap).

Gli struct devono avere visibilità pubblica.

In generale, uno struct deve avere almeno un campo (esistono rare eccezioni, ad esempio i tipi che rappresentano contratti di metadati e attributi). Tutti i campi di uno struct devono essere pubblici.

Uno struct non può essere generico né con parametri.

Interfacce

Un'interfaccia è un contratto costituito da un gruppo di membri di tipo correlati il cui utilizzo è definito, ma la cui implementazione non è . Una definizione di interfaccia specifica i membri dell'interfaccia, ovvero metodi, proprietà ed eventi. Non esiste alcuna implementazione associata a un'interfaccia.

Le interfacce senza parametri devono avere un ID di interfaccia univoco (noto anche come IID) specificato tramite guidAttribute. Un'interfaccia con parametri deve avere un ID interfaccia con parametri univoco (noto anche come PIID) specificato tramite guidAttribute. Il PIID viene usato per generare un IID per un'istanza di interfaccia con parametri specifica tramite l'algoritmo specificato in precedenza.

Un'interfaccia può avere visibilità pubblica o privata. Ciò riflette il fatto che alcune interfacce rappresentano contratti condivisi implementati da più classi WinRT, mentre altre interfacce rappresentano i membri implementati da una singola classe WinRT. Un'interfaccia di visibilità privata deve specificare la classe WinRT a cui è esclusiva tramite ExclusiveToAttribute. Le interfacce private possono essere implementate solo dalla classe WinRT specificata in ExclusiveToAttribute.

IInspectable e IUnknown

Quando si tratta di interfacce, WinRT non ha alcuna nozione di ereditarietà. C'è invece l'idea che un'interfaccia possa richiedere un'altra interfaccia. Per altre info, in particolare sulla parola chiave MIDL 3.0 requires , vedi Interfacce MIDL 3.0.

Tutte le interfacce WinRT richiedono implicitamente IInspectable; e a sua volta IInspectable richiede IUnknown. IUnknown definisce tre metodi: QueryInterface, AddRef e Release in base all'utilizzo COM tradizionale. IInspectable definisce tre metodi oltre ai metodi IUnknown: GetIids, GetRuntimeClassName e GetTrustLevel. Questi tre metodi consentono al client dell'oggetto di recuperare informazioni sull'oggetto. In particolare, IInspectable.GetRuntimeClassName consente al client di un oggetto di recuperare un nome di tipo WinRT che può essere risolto nei metadati per abilitare la proiezione del linguaggio.

L'interfaccia richiede

Come accennato in precedenza, un'interfaccia può specificare che richiede una o più interfacce che devono essere implementate in qualsiasi oggetto che implementa l'interfaccia in questione. Ad esempio, se IButton richiede IControl, qualsiasi classe che implementa IButton dovrà implementare anche IControl.

Ma né il sistema di tipi WinRT né l'ABI hanno un concetto di ereditarietà dell'interfaccia. L'idea di aggiungere nuove funzionalità implementando nuove interfacce che ereditano da interfacce esistenti (ad esempio, IFoo2 eredita da IFoo) non ha alcun significato. È vero che una proiezione del linguaggio WinRT può usare una relazione di ereditarietà per facilitare l'utilizzo in quel particolare linguaggio e una classe di runtime può usare l'ereditarietà, ma l'ereditarietà dell'interfaccia non esiste nel contesto della creazione MIDL 3.0 (vedere interfacce MIDL 3.0).

Interfacce con parametri

Le interfacce supportano la parametrizzazione dei tipi. Una definizione di interfaccia con parametri specifica un elenco di parametri di tipo oltre all'elenco di membri dell'interfaccia e alle interfacce necessarie. Un'interfaccia obbligatoria di un'interfaccia con parametri può condividere lo stesso elenco di argomenti di tipo, in modo che venga usato un singolo argomento di tipo per specificare l'istanza con parametri dell'interfaccia e dell'interfaccia richiesta, ad esempio IVector<T> requires IIterable<T>. La firma di qualsiasi membro , ovvero metodo, proprietà o evento, di un'interfaccia con parametri può fare riferimento a un tipo dall'elenco di argomenti di tipo dell'interfaccia con parametri , ad esempio IVector<T>.SetAt([in] UInt32 index, [in] T value).

Le terze parti non possono definire nuove interfacce con parametri. Sono supportate solo le interfacce con parametri definite dal sistema.

Delegati

Un delegato è un tipo WinRT che funge da puntatore a funzione indipendente dai tipi. Un delegato è essenzialmente un semplice oggetto WinRT che espone una singola interfaccia che eredita da IUnknown e definisce un singolo metodo denominato Invoke. Richiamando il delegato a sua volta richiama il metodo a cui fa riferimento. I delegati sono spesso (ma non esclusivamente) usati per definire gli eventi WinRT.

Un delegato WinRT è un tipo denominato e definisce una firma del metodo. Le firme del metodo delegato seguono le stesse regole per i parametri dei metodi di interfaccia. I nomi di firma e di parametro del metodo Invoke devono corrispondere alla definizione del delegato.

Analogamente alle interfacce, i delegati senza parametri devono avere un ID di interfaccia univoco (noto anche come IID) specificato tramite guidAttribute. L'IID del delegato viene usato come IID dell'interfaccia a metodo singolo usata per implementare il delegato. I delegati con parametri devono avere un ID interfaccia con parametri univoco (noto anche come PIID) specificato tramite guidAttribute. Il PIID viene usato per generare un IID per un'istanza del delegato con parametri specifica tramite l'algoritmo specificato in precedenza.

Un delegato deve avere visibilità pubblica.

IUnknown

Si noti che, a differenza delle interfacce WinRT, i delegati implementano IUnknown, ma non IInspectable. Ciò significa che non possono essere controllate per le informazioni sul tipo in fase di esecuzione.

Delegati con parametri

I delegati supportano la parametrizzazione dei tipi. Una definizione di delegato con parametri specifica un elenco di parametri di tipo oltre alla firma del metodo tradizionale, come specificato in precedenza. Nella firma del metodo qualsiasi parametro può essere specificato come uno dei tipi dell'elenco di argomenti di tipo dei delegati con parametri.

Le terze parti non possono definire nuovi delegati con parametri. Sono supportati solo i delegati con parametri definiti dal sistema.

Membri di interfaccia

Le interfacce WinRT supportano tre tipi di membri: metodi, proprietà ed eventi. Le interfacce potrebbero non avere campi dati.

Metodi

Le interfacce WinRT supportano metodi che accettano zero o più parametri e che restituiscono un HRESULT che indica l'esito positivo o negativo della chiamata al metodo. Un metodo può facoltativamente indicare un singolo parametro out da proiettare come valore restituito nelle lingue basate su eccezioni. Questo parametro restituito, se specificato, deve essere l'ultimo parametro nella firma del metodo.

Un metodo deve avere visibilità pubblica.

Un metodo non può utilizzare numeri variabili di argomenti. Un metodo potrebbe non avere parametri facoltativi, né parametri con valori predefiniti.

È possibile che un metodo non sia parametrizzato. I delegati e i metodi con parametri delle interfacce con parametri possono usare parametri di tipo del tipo contenitore nella firma del metodo.

Parametri

Tutti i parametri del metodo, ad eccezione dei parametri di lunghezza della matrice (descritti di seguito) devono avere un nome e un tipo. Si noti che i valori restituiti devono specificare un nome esattamente come i parametri. I nomi dei parametri del metodo, incluso il nome del tipo restituito, devono essere univoci nell'ambito del metodo.

Solo i parametri per delegati e membri con parametri delle interfacce con parametri possono specificare un tipo con parametri per il tipo di parametro. I metodi non possono essere parametrizzati singolarmente. I parametri possono sempre specificare istanze di tipo con parametri (ad esempio, IVector<int>) come tipo di parametro.

Tutti i parametri del metodo devono trovarsi esclusivamente nei parametri o out. I parametri in/out non sono supportati.

Mentre un metodo su un'interfaccia WinRT deve restituire un HRESULT, un metodo può facoltativamente indicare che il parametro out finale deve essere usato come valore restituito quando il metodo viene proiettato in lingue basate su eccezioni. Tali parametri sono noti come parametri [out, retval] dopo la sintassi MIDL usata per dichiararli. Quando viene specificato un parametro [out, retval] deve essere l'ultimo parametro nella firma del metodo.

Oltre a [out, retval] che deve essere visualizzato alla fine dell'elenco di parametri, non sono previsti altri requisiti di ordinamento per i parametri out.

Parametri matrice

I metodi WinRT supportano parametri di matrice conformi. Le matrici non possono mai essere usate ad eccezione dei parametri. Non possono essere tipi denominati autonomi e non possono essere usati come tipo di campo struct. I parametri della matrice possono essere usati come inparametri , oute retval .

WinRT supporta i parametri di matrice della maggior parte dei tipi WinRT, inclusi i tipi fondamentali (inclusi stringhe e GUID), struct, enumerazioni, delegati, interfacce e classi di runtime. Le matrici di altre matrici non sono consentite.

Poiché sono conformi, i parametri della matrice devono essere sempre preceduti immediatamente nell'elenco di parametri in base a un parametro per le dimensioni della matrice. Il parametro di dimensione della matrice deve essere un UInt32. Il parametro di dimensione della matrice non ha un nome.

WinRT supporta tre diversi stili di passaggio di matrici.

  • PassArray. Questo stile viene usato quando il chiamante fornisce una matrice al metodo . In questo stile, sia il parametro di dimensione della matrice che il parametro della matrice sono entrambi in parametri.
  • FillArray. Questo stile viene usato quando il chiamante fornisce una matrice per il riempimento del metodo, fino a una dimensione massima della matrice. In questo stile, il parametro array size è un in parametro, mentre il parametro della matrice è un out parametro. Quando si usa lo stile FillArray, il parametro della matrice può facoltativamente specificare uno degli altri parametri come parametro di lunghezza della matrice. I dettagli sono forniti di seguito.
  • ReceiveArray. Questo stile viene usato quando il chiamante riceve una matrice allocata dal metodo . In questo stile, il parametro di dimensione della matrice e il parametro della matrice sono entrambi out parametri. Inoltre, il parametro della matrice viene passato per riferimento (ovvero ArrayType**, anziché ArrayType*).

Nota

La combinazione di un out parametro di dimensione della matrice, ma un in parametro di matrice, non è valido in WinRT.

Quando un parametro di matrice viene usato come parametro [out, retval], il parametro di lunghezza della matrice deve essere un out parametro, ovvero solo lo stile ReceiveArray è valido per retval le matrici.

Parametro di lunghezza della matrice

Un parametro della matrice di stili FillArray può facoltativamente specificare un altro parametro come parametro di lunghezza della matrice. Se il parametro di dimensione della matrice richiesta specifica il numero massimo di elementi in una matrice fornita dal chiamante, il parametro di lunghezza della matrice specifica il numero di elementi effettivamente compilati dal chiamato.

Il parametro di lunghezza della matrice viene specificato con l'attributo LengthIs nel parametro della matrice.

Overload di un metodo

Nell'ambito di una singola interfaccia, più di un metodo può avere lo stesso nome. I metodi con lo stesso nome in un'interfaccia devono avere firme univoche. Non è possibile eseguire l'overload di proprietà ed eventi.

WinRT supporta l'overload sui tipi di parametro, ma favorisce l'overload sul numero di parametri di input, noto anche come arity del metodo. Questa operazione viene eseguita per supportare linguaggi dinamici e tipizzato in modo debole ,ad esempio JavaScript.

Quando un'interfaccia ha più metodi con lo stesso nome e numero di parametri di input, è necessario contrassegnare esattamente uno di questi metodi come predefinito. Di tutti i metodi di overload con lo stesso nome e il numero di parametri di input, solo il metodo contrassegnato come predefinito verrà proiettato da un linguaggio dinamico e tipizzato in modo debole. Se è presente un solo metodo di overload di un determinato nome e numero di parametri di input, contrassegnandolo come predefinito è valido, ma non obbligatorio.

Ai fini della determinazione dell'arità di un metodo, i parametri della matrice e il relativo parametro di lunghezza obbligatori sono considerati un singolo parametro. Gli stili PassArray e FillArray sono considerati un singolo parametro di input, mentre lo stile ReceiveArray è considerato un singolo parametro di output.

Quando più metodi in un'interfaccia hanno lo stesso nome, è necessario archiviare un nome univoco per ogni metodo in collisione in un overloadAttribute collegato al metodo . I metodi di overload predefiniti includono DefaultOverloadAttribute.

Overload degli operatori

WinRT non supporta l'overload degli operatori. I metodi non possono essere denominati usando i nomi di operatore speciali, ad esempio op_Addition specificati nella specifica dell'interfaccia della riga di comando ecMA 335, la partizione I, la sezione 10.3.

Proprietà

Una proprietà è una coppia di metodi get/set con nome e tipo corrispondenti visualizzati in alcune proiezioni del linguaggio come campi anziché metodi.

Una proprietà e i relativi metodi get/set devono avere visibilità pubblica.

Una proprietà deve avere un get metodo. Un metodo getter di proprietà non dispone di parametri e restituisce un valore del tipo di proprietà. Una proprietà con solo un get metodo viene chiamata proprietà di sola lettura.

Una proprietà può facoltativamente avere un set metodo. Un metodo setter di proprietà include un singolo parametro del tipo di proprietà e restituisce void. Una proprietà con un oggetto get e un set metodo viene chiamata proprietà di lettura/scrittura.

Le proprietà potrebbero non essere parametrizzate. Le proprietà delle interfacce con parametri possono usare parametri di tipo del tipo contenente come tipo di proprietà.

evento

Un evento è una coppia di metodi listener add/remove con il nome e il tipo delegato corrispondenti. Gli eventi sono un meccanismo per l'interfaccia per informare le parti interessate quando si verifica qualcosa di significativo.

Un evento e i relativi metodi di listener add/remove devono avere visibilità pubblica.

Un metodo listener eventi include un singolo parametro del tipo delegato dell'evento add e restituisce un Windows. Foundation.EventRegistrationToken. Un metodo listener evento remove include un singolo parametro della Windows. Tipo Foundation.EventRegistrationToken e restituisce void.

Gli eventi potrebbero non essere parametrizzati. Gli eventi delle interfacce con parametri possono usare parametri di tipo del tipo contenente come tipo delegato dell'evento.

Classi di runtime

WinRT consente di definire una classe. Una classe deve implementare una o più interfacce. Una classe non può implementare direttamente i membri del tipo, ovvero non può definire i propri metodi, proprietà o eventi. Una classe deve fornire un'implementazione di tutti i membri di tutte le interfacce implementate.

Esistono diversi tipi di interfacce, descritte in dettaglio di seguito.

  • Interfacce membro (incluse interfacce protette e sostituibili)
  • Interfacce statiche
  • Interfacce factory di attivazione
  • Interfacce factory di composizione

Non è possibile parametrizzare le classi di runtime. Una classe di runtime può implementare un'istanza dell'interfaccia con parametri, ovvero un'interfaccia con parametri con tutti i relativi parametri specificati, ovunque accetti in genere un'interfaccia non con parametri.

Una classe di runtime deve avere visibilità pubblica.

Una classe di runtime può implementare solo interfacce che non sono esclusive,ovvero non portare l'attributo exclusiveTo) o che sono esclusive per la classe di runtime in questione. Una classe di runtime potrebbe non implementare interfacce esclusive di una classe di runtime diversa. Esiste un'eccezione a questa regola: una classe componibile può implementare interfacce esclusive di una classe nella catena di derivazione contrassegnata come overridabile. Dettagli sulle interfacce sostituibili da seguire.

Interfaccia membro

Una classe di runtime può implementare zero o più interfacce membro. Le interfacce membro consentono alle classi di esporre funzionalità associate alle istanze della classe. Una classe di runtime specifica un elenco delle interfacce membro che implementa. Le voci nell'elenco delle interfacce membro implementate da una classe di runtime possono facoltativamente contenere informazioni sulla versione. Informazioni dettagliate sul controllo delle versioni delle classi di runtime da seguire.

Le interfacce membro vengono implementate direttamente nelle istanze della classe di runtime.

Le classi di runtime che implementano una o più interfacce membro devono specificare una delle interfacce membro per essere l'interfaccia predefinita. Le classi di runtime che implementano interfacce membro zero non specificano un'interfaccia predefinita.

Interfacce statiche

Le classi WinRT possono specificare zero o più interfacce statiche. Le interfacce statiche consentono alle classi di esporre funzionalità associate alla classe stessa, anziché a istanze specifiche della classe.

Una classe deve specificare almeno un membro o un'interfaccia statica. Una classe senza membri e nessuna interfaccia statica non è valida.

Le interfacce statiche vengono specificate tramite staticAttribute associato alla classe di runtime. StaticAttribute contiene un riferimento al riferimento dell'interfaccia statica e alle informazioni sulla versione. Informazioni dettagliate sul controllo delle versioni delle classi di runtime da seguire.

Anche se le interfacce statiche vengono dichiarate come parte della classe di runtime, non vengono effettivamente implementate nelle istanze della classe stessa. Invece, vengono implementati nella factory di attivazione della classe. Informazioni dettagliate sulle factory di attivazione da seguire.

Activation

Le classi di runtime supportano facoltativamente l'attivazione, ovvero la possibilità del sistema di produrre istanze di una classe specificata. Le classi devono implementare almeno un'interfaccia membro per supportare l'attivazione.

WinRT definisce tre meccanismi di attivazione: attivazione diretta (senza parametri del costruttore), attivazione della factory (con uno o più parametri del costruttore) e attivazione della composizione. Le classi non componibili possono supportare l'attivazione diretta e/o factory. Le classi componibili supportano solo l'attivazione componibile. Dettagli sulla composizione e sull'attivazione componibile da seguire.

Le classi che supportano l'attivazione diretta vengono attivate chiamando il metodo IActivationFactory.ActivateInstance nella factory di attivazione della classe. Questo metodo non accetta parametri e restituisce un'istanza appena attivata della classe di runtime. Informazioni dettagliate sulle factory di attivazione da seguire.

Le classi che supportano l'attivazione della factory definiscono una o più interfacce factory, ognuna a sua volta definisce uno o più metodi factory. Queste interfacce factory vengono implementate nella factory di attivazione della classe.

I metodi factory accettano uno o più in parametri e devono restituire un'istanza appena attivata della classe di runtime. Non sono consentiti altri out parametri oltre l'istanza della classe appena attivata. I metodi factory devono accettare uno o più parametri: l'attivazione della factory senza parametri non è consentita. L'attivazione diretta deve essere usata per l'attivazione senza parametri.

Le classi che supportano l'attivazione diretta o factory sono contrassegnate con ActivatableAttribute. ActivatableAttribute contiene informazioni sulla versione (dettagli sul controllo delle versioni della classe di runtime da seguire) e un riferimento facoltativo all'interfaccia factory. Le classi possono essere contrassegnate con più ActivatableAttributes, al massimo una per l'attivazione predefinita, più una per ogni interfaccia factory implementata dalla factory di attivazione della classe. Le classi contrassegnate con ActivatableAttribute potrebbero non essere contrassegnate anche con ComposableAttribute. Dettagli sulla composizione da seguire.

Composizione

Le classi di runtime supportano facoltativamente la composizione: la possibilità di combinare più istanze di classe in ciò che sembra essere un singolo oggetto dall'esterno. WinRT usa la composizione come forma di ereditarietà della classe di runtime.

Le classi WinRT possono facoltativamente comporre una singola classe base componibile, che a sua volta può comporre una singola classe di base componibile e così via. Una classe non deve essere componibile per comporre una classe base componibile. Le classi possono comporre solo con una classe componibile come classe di base. Una classe componibile non è necessaria per comporre un'altra classe componibile, ovvero la radice della gerarchia. I grafici circolari di composizione (ad esempio A compose B, che compone A) non sono consentiti.

In fase di esecuzione, una classe di composizione è un'aggregazione di oggetti WinRT, uno per ogni oggetto nella catena di composizione. Questi oggetti aggregati delegano l'identità e la durata all'oggetto attivato originariamente nella catena di composizione (denominato oggetto di controllo). Ogni oggetto della catena contiene un puntatore IInspectable non delegato alla classe che compone per chiamare metodi su interfacce di classe base composte, inclusi i metodi sulle interfacce protette. Ogni oggetto della catena ha un puntatore alla classe di controllo per delegare la durata e l'identità, nonché per chiamare metodi su interfacce sostituibili. Informazioni dettagliate sulle interfacce protette e sostituibili da seguire.

Si prenda l'esempio che Button compose Control, che a sua volta compone UIElement. In questo esempio un'istanza di Button aggrega un'istanza di Control , che a sua volta aggrega un'istanza di UIElement . Tutti e tre gli oggetti hanno un riferimento all'oggetto Button per controllare la durata e l'identità, nonché per eseguire query su interfacce sostituibili. Ogni oggetto ha un puntatore IInspectable all'oggetto composto (Button contiene un puntatore a Control; Il controllo contiene un puntatore a UIElement) per poter chiamare i metodi sulle interfacce implementate in classi composte, incluse le interfacce protette.

Una classe potrebbe non implementare interfacce definite nella classe composta, né alcuna classe nella catena di composizione, a meno che l'interfaccia non sia contrassegnata come overridabile nella classe componibile. Dettagli sulle interfacce sostituibili da seguire.

Una classe componibile deve essere contrassegnata con una o più ComposableAttributes. ComposableAttribute contiene un riferimento all'interfaccia della factory di composizione, indipendentemente dal fatto che i metodi factory dell'interfaccia di composizione possano essere usati per controllare l'attivazione dell'oggetto o meno, nonché le informazioni sulla versione. Informazioni dettagliate sulle interfacce della factory di composizione e sul controllo delle versioni da seguire. Una classe può essere contrassegnata con più ComposableAttributes, una per ogni interfaccia factory di composizione implementata dalla factory di attivazione della classe.

La proiezione del linguaggio JavaScript non supporta la composizione della classe. Di conseguenza, le classi componibili e le classi che compongono le classi componibili, devono essere contrassegnate con WebHostHiddenAttribute che indica che JavaScript non deve tentare di proiettare questi tipi.

Le terze parti possono definire solo classi che compongono altre classi componibili. Potrebbe non essere possibile definire la propria classe radice componibile.

Attivazione componibile

Una classe componibile deve definire una o più interfacce factory di composizione, che a sua volta implementano uno o più metodi factory di composizione. Le interfacce factory di composizione vengono implementate nella factory di attivazione della classe. Dettagli sulle factory di attivazione da seguire.

Un'interfaccia factory di composizione viene usata per creare istanze componibili della classe . Un'interfaccia factory componibile dichiara zero o più metodi factory componibili che possono essere usati per attivare istanze della classe a scopo di composizione. Si noti che è legale avere un'interfaccia factory componibile con zero metodi factory. Ciò implica che la classe può essere usata per la composizione, ma che le terze parti potrebbero non comporre direttamente la classe, ovvero i metodi per creare istanze sono solo interni.

Una classe componibile dichiara se i metodi factory in una determinata interfaccia factory di composizione possono essere usati per attivare la classe direttamente come oggetto di controllo. Le interfacce factory componibili contrassegnate come pubbliche possono essere usate per attivare direttamente una classe come oggetto di controllo, nonché indirettamente per attivare una classe come oggetto composto. Le interfacce factory componibili contrassegnate come protette possono essere usate solo per attivare indirettamente una classe come oggetto composto. Le classi componibili possono sempre essere attivate come oggetti composti.

Un'interfaccia factory di composizione deve essere exclusiveto la classe di runtime implementata da .

Analogamente a un metodo factory di attivazione, un metodo factory di composizione deve restituire un'istanza della classe componibile. Inoltre, un metodo factory di composizione ha due parametri aggiuntivi: il parametro IInspectable* [in] e il parametro IInspectable** [out] non delegato. Un metodo factory di composizione può facoltativamente avere parametri aggiuntivi in . Se specificato, i parametri aggiuntivi nei parametri devono verificarsi all'inizio della firma del metodo, prima che i parametri imposti elencati in precedenza. Un metodo factory di composizione potrebbe non avere parametri aggiuntivi out oltre i parametri IInspectable** non delegati e i parametri del valore restituito.

Quando viene attivata una classe componibile per la composizione (ad esempio , Control o UIElement quando viene attivata un'istanza button ), un puntatore all'oggetto che controlla l'identità e la durata viene passato tramite il parametro IInspectable* [in] di controllo. Il metodo factory componibile restituisce l'istanza appena attivata come valore restituito. Questa istanza delega tutte le funzionalità di gestione delle identità e della durata al controllo IInspectable* fornito. Inoltre, il metodo factory componibile restituisce un puntatore a un IInspectable non delegato* che la classe di composizione può usare per richiamare i metodi in una classe composta.

Quando una classe componibile viene attivata come classe di controllo (ad esempio, Button nell'esempio precedente), gli stessi metodi factory componibili vengono usati come per l'attivazione per la composizione. Quando si attiva direttamente una classe componibile, viene passato Null per il parametro *IInspectable* di controllo. Si tratta di un indicatore della classe componibile che viene attivata come classe di controllo. Quando una classe di controllo crea l'istanza della classe che compone, passa un riferimento a se stesso come parametro IInspectable* di controllo. Il metodo factory componibile restituisce l'istanza della classe di controllo come valore restituito. Il parametro IInspectable** [out] non delegato viene ignorato dal codice client quando si attiva una classe componibile di controllo.

Basandosi sull'esempio precedente Button ->Control ->UIElement , la classe button viene attivata chiamando uno dei metodi factory di composizione e passando Null per il parametro esterno. Il pulsante attiva a sua volta un'istanza di Control , passando un riferimento a se stesso come parametro esterno. Il controllo a sua volta attiva un'istanza di UIElement , passando il riferimento esterno ricevuto come parametro esterno. Il metodo factory UIElement tornerà a Control the newly created UIElement nel parametro di istanza, nonché a un riferimento all'IInspectable non delegabile di UIElement nel parametro interno. Il metodo Control factory tornerà a Button il controllo appena creato nel parametro dell'istanza, nonché un riferimento al parametro interno che non delega IInspectable di Control. La factory di composizione Button torna al codice chiamante il pulsante appena creato nel parametro dell'istanza e null per il parametro interno.

È possibile che una classe venga talvolta attivata per la composizione e altre volte attivata come classe di controllo. Ad esempio, se RadioButton ha composto Button, Button verrebbe attivato per la composizione quando è stato attivato un controllo RadioButton ; ma attivato come classe di controllo quando Button è stato attivato direttamente. In entrambi i casi, la classe Control composta da Button verrebbe attivata per la composizione.

Interfacce protette

Una classe componibile può dichiarare zero o più interfacce membro da proteggere. Una classe non componibile potrebbe non dichiarare le interfacce membro da proteggere. Solo il codice in una classe che compone una classe componibile (direttamente o indirettamente) può eseguire una query per e usare interfacce dichiarate dalla classe componibile come protette. Il codice dall'esterno della catena di composizione non può eseguire query per, né usare, interfacce dichiarate dalla classe componibile come protette.

Ad esempio, se UIElement dichiara un'interfaccia protetta IUIElementProtected, solo le classi che compongono UIElement, incluse la composizione diretta (Control) e indiretta (Button), possono eseguire una query per e usare l'interfaccia IUIElementProtected .

Interfacce sostituibili

Una classe componibile può dichiarare zero o più interfacce membro di cui eseguire l'override. È possibile eseguire query su un'interfaccia sostituibile solo per una catena di composizione, analogamente alle regole relative all'accesso alle interfacce protette descritte in precedenza. Tuttavia, se un'interfaccia protetta può essere implementata solo dalla classe che l'ha originariamente dichiarata, le interfacce sostituibili possono essere implementate di nuovo dalle classi che compongono la classe che ha implementato l'interfaccia sostituibile.

In fase di esecuzione, qualsiasi codice di classe componibile che sfrutta l'interfaccia sostituibile deve Eseguire QueryInterface per l'interfaccia tramite il puntatore IInspectable* di controllo usato per la delega di identità e durata. Questo puntatore restituisce l'implementazione dell'interfaccia sottoponibile a override nella catena di composizione, ovvero più vicina all'istanza della classe di controllo. Una classe che desidera accedere alle interfacce sostituibili della classe che compone può farlo tramite il riferimento non delegabile che una classe componibile contiene alla classe composta.

Prendiamo l'esempio che UIElement dichiara un'interfaccia sostituibile IUIElementOverridable. In tal caso, le classi che derivano da UIElement, incluse la derivazione diretta (Control) e indiretta (Button), possono implementarla. Se il codice in UIElement doveva accedere alle funzionalità in IUIElementOverridable, UIElement eseguirà una query sul controllo IInspectable per ottenere la prima implementazione nella catena di composizione. Se Sia Control che Button implementano entrambi IUIElementOverridable, l'implementazione button viene restituita quando viene eseguita una query sul controllo IInspectable . Se Button vuole accedere alla funzionalità della classe composta, può usare l'interfaccia IInspectable non delegata restituita dal metodo factory di composizione per eseguire una query sulla classe di base per tale interfaccia.

Factory di attivazione

Una classe di runtime ha facoltativamente una factory di attivazione. Una classe di runtime deve avere una factory di attivazione se la classe è attivabile, componibile o dispone di interfacce statiche. La factory di attivazione per una classe può essere recuperata dal sistema in fase di esecuzione tramite la funzione RoGetActivationFactory Win32.

Le factory di attivazione devono implementare l'interfaccia IActivationFactory . Tuttavia, solo le classi che supportano l'attivazione diretta forniscono un'implementazione del metodo singolo di IActivationFactoryActivateInstance. Le classi che non supportano l'attivazione diretta devono restituire E_NOTIMPL da IActivationFactory.ActivateInstance.

La factory di attivazione deve implementare tutte le interfacce factory di attivazione, le interfacce factory di composizione e le interfacce statiche definite nella classe di runtime.

Non esiste alcuna garanzia che le proiezioni del linguaggio mantengano una singola istanza della factory di attivazione per la durata della factory. Gli autori di classi WinRT che devono salvare informazioni di lunga durata per l'accesso ai membri statici devono archiviarla in un punto esterno alla factory di attivazione.

Proiezione basata su classi

Anche se WinRT è principalmente un modello di programmazione basato su interfaccia, le classi di runtime forniscono un modello di programmazione basato su classi che è meglio allineato ai linguaggi di programmazione moderni, mainstream e orientati agli oggetti. Le proiezioni del linguaggio devono proiettare una classe di runtime come singola entità, anziché come un contenitore di interfacce che lo sviluppatore deve gestire separatamente.

Per ottenere questo modello basato su classi, è previsto che le proiezioni del linguaggio progettino membri di tipo dalle interfacce membro di una classe come membri diretti della classe. Le proiezioni del linguaggio devono proiettare membri del tipo dalle interfacce statiche di una classe come membri della classe statica. Infine, le proiezioni del linguaggio prevedono metodi di attivazione del progetto (attivazione diretta e interfacce delle interfacce factory e componibili) come costruttori di classi.

Per facilitare questa proiezione basata su classi, i metadati per le classi di runtime specificano un membro di classe per tutti i metodi, le proprietà e gli eventi di ogni interfaccia implementata. Ogni membro della classe è collegato in modo esplicito al membro dell'interfaccia in cui è stato originariamente definito. Ciò consente alle proiezioni del linguaggio di esporre la classe come singola entità, gestendo tutte le query di interfaccia e il conteggio dei riferimenti sotto le quinte per conto dello sviluppatore.

Per impostazione predefinita, ogni membro dell'interfaccia implementato viene proiettato come membro di classe. Tuttavia, poiché le classi di runtime possono implementare più interfacce e versioni indipendenti nel tempo (dettagli sul controllo delle versioni da seguire), è possibile che si verifichino conflitti di nomi per i membri definiti in interfacce diverse implementate da una singola classe di runtime.

Quando si verificano conflitti, la proiezione predefinita dei membri della classe è impossibile. Se si verificano conflitti tra interfacce aggiunte in versioni separate, il membro in collisione dalla versione meno recente viene proiettato come membro della classe. Quando si verificano conflitti tra interfacce aggiunte nella stessa versione, nessuno dei membri in collisione viene proiettato come membri della classe. Si noti che i metodi con nomi in collisione sono consentiti, purché tutte le versioni siano di diversa arità , come descritto in Overload dei metodi.

I membri dell'interfaccia non proiettati come membri della classe devono essere resi disponibili per gli sviluppatori. In genere, si tratta di un'operazione eseguita da un operatore di cast o di ricerca dinamica, consentendo allo sviluppatore di specificare l'interfaccia e il metodo specifici da richiamare.

Per risolvere i conflitti di nomi dei metodi, le classi di runtime possono specificare nomi alternativi per i metodi nel membro e nelle interfacce statiche implementate. Questo nome alternativo viene usato dalla proiezione del linguaggio per fornire l'accesso non ambiguo ai nomi dei metodi in collisione da un'istanza di classe. Anche se la classe di runtime può fornire un nome di metodo alternativo, la firma del metodo, i parametri e tutti gli attributi associati al metodo o i relativi attributi devono comunque corrispondere esattamente alla definizione dell'interfaccia originale.

Poiché l'attivazione diretta, i metodi factory e i metodi factory di composizione vengono proiettati come costruttori di classi, tutti vengono proiettati nella classe di runtime come se avessero lo stesso nome. Tutti i metodi in tutte le interfacce factory devono avere firme univoche, devono favorire l'overload basato sull'arity rispetto all'overload basato sui tipi e devono usare DefaultOverloadAttribute per disambiguare i metodi factory della stessa arità.

Controllo delle versioni delle classi

Le classi di runtime sono disponibili in modo aggiuntivo per la versione. Le versioni successive di una determinata classe di runtime possono specificare interfacce aggiuntive di tutti i tipi, con ulteriori dettagli sui singoli tipi di interfaccia riportati di seguito. Le interfacce preesistenti specificate da una classe potrebbero non essere mai rimosse o modificate senza compromettere la compatibilità con le versioni precedenti.

Controllo delle versioni dell'interfaccia membro

Le interfacce membro nelle classi di runtime sono modificabili in modo aggiuntivo. Le versioni successive di una determinata classe di runtime possono implementare interfacce membro aggiuntive, anche se la classe non ha mai implementato interfacce membro in precedenza. Le versioni successive di una determinata classe di runtime componibile possono implementare interfacce aggiuntive protette e sostituibili.

Le interfacce implementate da una classe di runtime contengono facoltativamente VersionAttribute per distinguere quando sono state aggiunte interfacce specifiche al tipo di classe di runtime. I valori di implementazione dell'interfaccia senza VersionAttribute sono considerati con lo stesso valore della versione del tipo di classe runtime contenitore.

Controllo delle versioni dell'interfaccia statica

Le interfacce statiche nelle classi di runtime sono disponibili in modo aggiuntivo per la versione. Le versioni successive di una determinata classe di runtime possono implementare interfacce statiche aggiuntive, anche se la classe non ha mai implementato interfacce statiche in precedenza.

StaticAttribute include un parametro UInt32 per il numero di versione, che definisce la versione di Windows che ha aggiunto tale supporto per l'attivazione.

Controllo delle versioni di attivazione

Il supporto dell'attivazione per le classi di runtime è addizione per la versione. Le versioni successive di una determinata classe di runtime possono implementare meccanismi di attivazione aggiuntivi, anche se la classe non ha mai implementato un meccanismo di attivazione. Si noti che le classi componibili non sono attivabili e pertanto potrebbero non aggiungere il supporto per l'attivazione.

Si noti che una classe che supporta l'attivazione diretta può aggiungere solo nuove interfacce di attivazione della factory. Una classe che in precedenza supportava solo l'attivazione factory può aggiungere il supporto per l'attivazione diretta e le nuove interfacce di attivazione della factory.

ActivatableAttribute include un parametro UInt32 per il numero di versione. Il numero di versione per ActivatableAttribute definisce la versione di Windows che ha aggiunto tale supporto per l'attivazione.

Controllo delle versioni di composizione

Il supporto della composizione per le classi di runtime è modificabile in modo aggiuntivo. Le versioni successive di una determinata classe di runtime componibile possono implementare meccanismi di composizione aggiuntivi, purché la classe sia stata definita componibile al momento della creazione. Le classi componibili potrebbero non aggiungere il supporto per l'attivazione.

ComposableAttribute include un parametro UInt32 per il numero di versione. Il numero di versione per ComposableAttribute definisce la versione di Windows che ha aggiunto tale supporto per la composizione.

Attributi personalizzati

WinRT supporta la definizione di attributi di metadati personalizzati. Tutti i costrutti nel sistema di tipi WinRT possono contenere attributi di metadati personalizzati. Sono inclusi tutti i tipi denominati (enumerazioni, struct, delegati, interfacce, classi e così via) e singoli elementi contenuti all'interno di costrutti di tipo (ad esempio metodi, parametri e così via).

Gli attributi personalizzati sono denominati come altri tipi WinRT. Tuttavia, non sono attuabili. Sono puramente un costrutto di dati.

Gli attributi personalizzati definiscono uno schema di dati di parametri posizionali o campi denominati. Un attributo personalizzato non può usare sia parametri posizionali che campi denominati, ma deve scegliere uno o l'altro. I tipi di parametri e campi di un attributo personalizzato sono limitati ai tipi fondamentali, alle enumerazioni e ai riferimenti a altri tipi WinRT. Non è consentito alcun altro parametro o tipo di campo.

Gli attributi personalizzati che usano parametri posizionali devono definire uno o più set validi di parametri posizionali. Ogni set deve specificare zero o più parametri posizionali. Un'istanza dell'attributo personalizzato deve specificare un singolo set di parametri posizionali, nonché i dati per ogni parametro posizionale nel set selezionato.

Un attributo personalizzato che usa campi denominati specifica zero campi con nomi e tipi. Un'istanza dell'attributo personalizzato deve specificare le coppie nome/valore per i campi da specificare. Un'istanza può specificare valori per tutte, alcune o nessuna delle coppie nome/valore.

È valido per un attributo non avere parametri posizionali né campi denominati.

Un attributo personalizzato deve avere visibilità pubblica.

Un attributo può specificare i tipi di costrutti di tipo WinRT a cui può essere associato tramite AttributeUsageAttribute.

Le terze parti non possono definire attributi personalizzati. Sono supportati solo gli attributi personalizzati definiti dal sistema.