Share via


Sistema de tipos de Windows Runtime (WinRT)

Notas generales

Todos los tipos, excepto los tipos fundamentales, deben estar incluidos en un espacio de nombres. No es válido que un tipo esté en el espacio de nombres global.

Los tipos proporcionados por Windows están incluidos en el espacio de nombres Windows.*. Los tipos de WinRT no proporcionados por Windows (incluidos los tipos de WinRT proporcionados por otras partes de Microsoft) deben residir en un espacio de nombres distinto de Windows.*.

A excepción de las interfaces, todos los tipos de WinRT deben tener visibilidad pública. Opcionalmente, las interfaces de WinRT pueden tener visibilidad privada. Todos los demás tipos de WinRT definidos por el usuario (structs, clases, enumeraciones, delegados, atributos) deben tener visibilidad pública.

WinRT no admite tipos anidados. Ningún tipo winRT puede incluir otro tipo; no se puede anidar ningún tipo winRT dentro de otro tipo.

No todos los aspectos del sistema de tipos de WinRT están disponibles para ti, como desarrollador de terceros.

  • WinRT admite la parametrización de interfaces y delegados. Sin embargo, en esta versión WinRT no admite la definición de tipos parametrizados por terceros. Solo se admiten los tipos con parámetros incluidos en el sistema en el espacio de nombres Windows.*.

  • WinRT admite la composición de clases como mecanismo de herencia en tiempo de ejecución. Sin embargo, en esta versión WinRT no admite la definición de una clase compuesta raíz. Solo se admiten las clases compuestas raíz incluidas en el sistema en el espacio de nombres Windows.*.

Los espacios de nombres y los nombres de tipo de WinRT conservan mayúsculas de minúsculas, pero no distinguen, de forma similar al sistema de archivos de Windows y al Registro de Windows. Esto significa que no puede tener espacios de nombres ni nombres de tipo que varían solo por mayúsculas y minúsculas. Por ejemplo, no puede tener Foo.SomeType y foo. AnotherType, ni puede tener Foo.SomeType y Foo.someType.

Un identificador de WinRT debe ajustarse a la gramática siguiente. Tenga en cuenta que solo se admiten los caracteres definidos en Unicode 3.0 y versiones anteriores.

    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)

Tipos parametrizados

WinRT admite la parametrización de tipos de interfaces y delegados. Los tipos con parámetros permiten definir una familia de interfaces que se pueden procesar polimórficamente en lenguajes de programación que admiten polimorfismo paramétrico.

Una creación de instancias de tipo con parámetros se produce cuando se especifica un tipo con parámetros con una lista de argumentos de tipos en un contexto de tipo, como una posición de parámetro de método. Por ejemplo, HRESULT foo(X<Y> x) crea una instancia del tipo con parámetros denominado por X con el tipo Y como su primer y único argumento de tipo.

A una interfaz o delegado de WinRT sin parámetros se le asigna un GUID para identificar de forma única la interfaz subyacente como distinta de otras interfaces del mismo objeto. En su lugar, a una interfaz con parámetros (por ejemplo, IVector<T>) o delegado (por ejemplo, EventHandler<T>) se le asigna un identificador de interfaz con parámetros (PIID), que es un GUID que identifica de forma única este tipo con parámetros. Esto no es un IID. Este GUID se usa para generar IID para instancias de tipo con parámetros (por ejemplo, IVector<int>).

Lista de argumentos de tipo con parámetros

Estos tipos de WinRT pueden aparecer en la lista de argumentos de un tipo con parámetros.

  • Tipos fundamentales de WinRT (por ejemplo, Boolean, Int32, String, Guid, etc.)
  • Enumeraciones de WinRT
  • Estructuras de WinRT
  • Interfaces de WinRT
  • Delegados de WinRT
  • Clases en tiempo de ejecución de WinRT
  • Otras instancias de tipo con parámetros (por ejemplo, IVector<IVector<int>>) Cualquier otro tipo no aparece en una lista de argumentos de tipo con parámetros. Por ejemplo, matrices.

Instancias de tipo con parámetros

Una instancia de tipo con parámetros puede aparecer en cualquier contexto que pueda aparecer un tipo no parametrizado. Se puede usar una instancia de interfaz parametrizada en cualquier lugar en el que se pueda usar una interfaz, como en la lista de interfaces implementadas por una clase en tiempo de ejecución. Se puede usar una instancia de delegado parametrizada en cualquier lugar en el que se pueda usar un delegado, como en la definición de un evento.

Puede aparecer un parámetro de tipo con parámetros: en la interfaz parametrizada o en la definición de delegado; o bien, cualquier lugar en el que pueda aparecer normalmente un tipo normal. Si aparece un parámetro donde solo puede aparecer una interfaz, ese parámetro está restringido a ser una interfaz. Si un parámetro aparece en un contexto en el que puede aparecer cualquier tipo, ese parámetro no está restringido; y así sucesivamente. Los argumentos de las instancias de tipo con parámetros deben cumplir todas estas restricciones.

Generación de guid para tipos con parámetros

El algoritmo de generación guid debe cumplir estos requisitos.

  • Cuando se crea una instancia de un tipo con parámetros dos veces con los mismos argumentos, se deben asignar ambas instancias al mismo cuerpo de interfaz o delegado y al mismo IID.
  • Si se crean instancias de dos tipos con parámetros diferentes, incluso con los mismos argumentos, debe ser estadísticamente improbable que se les asigne el mismo IID.
  • Si se crea una instancia de un tipo con parámetros dos veces, pero con argumentos diferentes, debe ser estadísticamente improbable que se asignen las dos instancias al mismo IID.

Nota:

No se permite que se cree una instancia de un tipo con parámetros con la misma creación de instancias que un argumento, o como argumento para cualquier otro tipo con parámetros que aparezca en la lista de argumentos (es decir, creación de instancias circulares). Por ejemplo, si X = Foo<Y>se ha infringido la no circularidad , y Y = Foo<X>. Sin embargo, si X = Foo<Y> y Y = Foo<int>, se ha mantenido la no circularidad.

El algoritmo de creación de instancias es el siguiente.

  1. A cada tipo con parámetros se le asigna un identificador de interfaz con parámetros por su autor, piID abreviado. Tenga en cuenta que un PIID no es un IID, ni se pasa como argumento a QueryInterface. El autor debe asegurarse de que el PIID es único para el tipo con parámetros.
  2. La firma de tipo de un tipo base es una cadena de octeto ASCII (consulte la tabla siguiente). Por ejemplo, Int32 es "i4".
  3. La firma de tipo de una interfaz que no es una instancia de interfaz parametrizada es su IID codificado en ASCII en forma discontinua y delimitado por llaves. Por ejemplo, "{00000000-0000-0000-0000-000000000000}".
  4. La firma de tipo para un delegado que no es una instancia de delegado con parámetros es la cadena "delegate" y, a continuación, el IID como con interfaces. La gramática detallada aparece a continuación.
  5. El guid de un tipo con parámetros se calcula según esta gramática.
    • según UUID rfc 4122, calcule el hash generado ver 5 sha-1 de signature_octets: usa un único guid de winrt pinterface/pintergroup como espacio de nombres tal y como se describe en rfc 4122/4.3, y la firma del pinterface/pintergroup y los argumentos con los que se crea una instancia como cadena de nombre.
    • La creación de instancias de pinterface se asigna a este guid y la firma de 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. Cuando se pasa una instancia de tipo p como argumento a una pinterface, la firma calculada en el paso 3 se usa como firma de tipo en el elemento gramatical "pinterface_instance_signature" o "pdelegate_instance_signature", según corresponda.

Estos nombres se usan para los tipos base cuando aparecen.

  • UInt8 se asigna a "u1"
  • Int32 se asigna a "i4"
  • UInt32 se asigna a "u4"
  • Int64 se asigna a "i8"
  • UInt64 se asigna a "u8"
  • Un solo mapa a "f4"
  • El doble se asigna a "f8"
  • Boolean se asigna a "b1"
    • Tenga en cuenta que, para obtener compatibilidad con parámetros de tipo booleano , debe agregar /Yc:wchar_t para habilitar wchar_t como un tipo integrado.
  • Char16 se asigna a "c2"
  • La cadena se asigna a "string"
  • Guid se asigna a "g16"

Los nombres anteriores distinguen mayúsculas de minúsculas. Con la excepción de String, el nombre de tipo usa un solo carácter para sugerir el tipo de datos, seguido de su tamaño en bytes. Estos nombres se eligieron: para ser concisos (para evitar tamaños grandes en firmas de tipo struct); para que no aparezca confusamente similar al nombre de WinRT, el nombre RIDL ni el nombre de proyección del lenguaje para cualquier tipo; y siguen siendo aproximadamente legibles.

Para enum_type_signature, el único valor "underlying_type" válido es el de Int32 o UInt32.

Para struct_type_signature, args es una lista en orden de type_signatures para los campos de la estructura. Pueden ser tipos base u otros tipos de estructura.

Struct_name y enum_name son calificados por el espacio de nombres, usando el punto "." como delimitadores. Por ejemplo, "espacio de nombres X { struct A{ int; }; }" se convierte en "struct(X.A;i4)".

Default_interface debe ser la interfaz, la instancia de p-interface, el delegado o la instancia de p-delegate que se especificó como predeterminada en el cuerpo de la clase en tiempo de ejecución o del grupo de interfaz, mediante el atributo IDL '[default]'.

Tenga en cuenta que se omiten los atributos personalizados; se supone que no tiene ningún efecto en la serialización.

Control de versiones

Todos los tipos de WinRT excepto los tipos fundamentales deben tener un atributo Version. Las proyecciones de lenguaje usan la información del atributo Version para habilitar la compatibilidad con versiones anteriores y para escenarios de iluminación. Los tipos de terceros deben incluir un atributo Version, pero las proyecciones del lenguaje deben omitirla. Los componentes de WinRT de terceros se empaquetan exclusivamente en la aplicación, por lo que nunca pueden cambiar la versión independientemente de la propia aplicación.

El atributo Version se puede aplicar opcionalmente a los miembros de la interfaz (métodos, propiedades y eventos). Esto está pensado para la creación de clases de alto nivel en C#/VB y C++/CX. Los atributos de versión de los miembros de la interfaz, incluso Windows miembros de la interfaz del sistema, deben omitirse en tiempo de ejecución mediante proyecciones de lenguaje.

El atributo Version incluye un parámetro de constructor entero de 32 bits sin signo. Para Windows tipos de WinRT, este valor es el valor NTDDI de la versión de Windows la construcción de tipo asociada se definió por primera vez. En el caso de los tipos de terceros, el significado de este valor es hasta el autor del tipo.

Windows estructuras del sistema, delegados e interfaces son inmutables una vez definidas. Es posible que nunca se modifiquen en ninguna versión posterior de Windows.

Windows enumeraciones del sistema y clases en tiempo de ejecución son controlables aditivamente. Las enumeraciones pueden agregar nuevos valores de enumeración en versiones posteriores de Windows. Las clases pueden agregar nuevas interfaces implementadas (como static, activation factory, composition factory, overridable e protected interfaces) en versiones posteriores de Windows. En las secciones de enumeraciones y clases en tiempo de ejecución se incluyen más detalles sobre el control de versiones adicionales.

Espacios de nombres

Un espacio de nombres es un ámbito de nomenclatura que se usa para organizar el código y para evitar colisiones de nomenclatura. Todos los tipos con nombre del sistema de tipos de WinRT (enumeraciones, estructuras, delegados, interfaces y clases en tiempo de ejecución) residen en un espacio de nombres. Un espacio de nombres puede contener otros espacios de nombres.

Tipos fundamentales

El sistema de tipos winRT incluye un conjunto básico de tipos primitivos integrados.

Tipo de WinRT Descripción del tipo
Int16 un entero de 16 bits con signo
Int32 un entero de 32 bits con signo
Int64 un entero de 64 bits con signo
UInt8 un entero de 8 bits sin signo
UInt16 entero de 16 bits sin signo
UInt32 un entero de 32 bits sin signo
UInt64 entero de 64 bits sin signo
Single un número de punto flotante IEEE 754 de 32 bits
Double un número de punto flotante IEEE 754 de 64 bits
Char16 un valor no numérico de 16 bits que representa una unidad de código UTF-16
Boolean un valor booleano de 8 bits
String una secuencia inmutable de Char16 que se usa para representar texto
Guid Guid estándar de 128 bits

Enumeraciones

Un tipo de enumeración es un tipo de valor distinto con un conjunto de constantes con nombre.

Cada tipo de enumeración tiene un tipo entero correspondiente denominado tipo subyacente del tipo de enumeración. Los únicos tipos subyacentes de enumeración legal en WinRT son Int32 y UInt32.

Una enumeración con un tipo subyacente de UInt32 debe llevar FlagsAttribute. Una enumeración con un tipo subyacente de Int32 no debe llevar FlagsAttribute.

Una enumeración debe tener visibilidad pública.

Control de versiones de enumeración

Una enumeración es aditivamente versionable. Las versiones posteriores de una enumeración determinada pueden agregar valores (también conocidos como constantes con nombre). Es posible que los valores preexistentes no se quiten ni cambien. Opcionalmente, los valores de enumeración llevan versionAttribute para distinguir cuándo se agregaron valores específicos al tipo de enumeración. Los valores de enumeración sin versionAttribute se consideran que tienen el mismo valor de versión que el tipo de enumeración envolvente.

Estructuras

Una estructura es un tipo de registro con uno o varios campos. Las estructuras siempre se pasan y devuelven por valor. Los campos de estructura solo pueden ser primitivos, enumeraciones, structs, cadenas e IReference<T> (los dos últimos son los únicos tipos de campo asignados al montón).

Las estructuras deben tener visibilidad pública.

En general, un struct debe tener al menos un campo (hay excepciones poco frecuentes, como tipos que representan contratos de metadatos y atributos). Todos los campos de una estructura deben ser públicos.

Una estructura no puede ser genérica ni parametrizada.

Interfaces

Una interfaz es un contrato que consta de un grupo de miembros de tipo relacionados cuyo uso se define, pero cuya implementación no es. Una definición de interfaz especifica los miembros de la interfaz: métodos, propiedades y eventos. No hay ninguna implementación asociada a una interfaz.

Las interfaces no parametrizadas deben tener un identificador de interfaz único (también conocido como IID) especificado a través de guidAttribute. Una interfaz parametrizada debe tener un identificador de interfaz con parámetros único (también conocido como PIID) especificado a través de guidAttribute. El PIID se usa para generar un IID para una instancia de interfaz parametrizada específica a través del algoritmo especificado anteriormente.

Una interfaz puede tener visibilidad pública o privada. Esto refleja el hecho de que algunas interfaces representan contratos compartidos implementados por varias clases de WinRT, mientras que otras interfaces representan miembros implementados por una sola clase winRT. Una interfaz de visibilidad privada debe especificar la clase WinRT a la que es exclusiva a través de ExclusiveToAttribute. La clase WinRT especificada en ExclusiveToAttribute solo puede implementar interfaces privadas.

IInspectable e IUnknown

En lo que respecta a las interfaces, WinRT no tiene ninguna noción de herencia. En su lugar, hay la idea de que una interfaz puede requerir otra interfaz. Para obtener más información, en concreto sobre la palabra clave MIDL 3.0 requires , consulta Interfaces de MIDL 3.0.

Todas las interfaces de WinRT requieren implícitamente IInspectable; y a su vez IInspectable requiere IUnknown. IUnknown define tres métodos: QueryInterface, AddRef y Release según el uso com tradicional. IInspectable define tres métodos además de los métodos IUnknown: GetIids, GetRuntimeClassName y GetTrustLevel. Estos tres métodos permiten al cliente del objeto recuperar información sobre el objeto. En concreto, IInspectable.GetRuntimeClassName permite al cliente de un objeto recuperar un typename de WinRT que se puede resolver en metadatos para habilitar la proyección de lenguaje.

La interfaz requiere

Como se mencionó anteriormente, una interfaz puede especificar que requiere una o varias otras interfaces que se deben implementar en cualquier objeto que implemente la interfaz en cuestión. Por ejemplo, si IButton requiere IControl, cualquier clase que implemente IButton también tendría que implementar IControl.

Pero ni el sistema de tipos winRT ni la ABI tienen un concepto de herencia de interfaz. Por lo tanto, la idea de agregar nueva funcionalidad mediante la implementación de nuevas interfaces que heredan de las interfaces existentes (por ejemplo, IFoo2 hereda de IFoo) no tiene ningún significado. Es cierto que una proyección de lenguaje WinRT puede usar una relación de herencia para facilitar el consumo en ese idioma en particular, y una clase en tiempo de ejecución puede usar la herencia, pero la herencia de interfaz no existe en el contexto de la creación de MIDL 3.0 (consulte interfaces MIDL 3.0).

Interfaces parametrizadas

Las interfaces admiten la parametrización de tipos. Una definición de interfaz parametrizada especifica una lista de parámetros de tipo además de la lista de miembros de interfaz e interfaces necesarias. Una interfaz necesaria de una interfaz parametrizada puede compartir la misma lista de argumentos de tipo, de modo que se usa un único argumento de tipo para especificar la instancia parametrizada de la interfaz y la interfaz que requiere (por ejemplo, IVector<T> requires IIterable<T>). La firma de cualquier miembro (es decir, método, propiedad o evento) de una interfaz con parámetros puede hacer referencia a un tipo de la lista de argumentos de tipo de la interfaz parametrizada (por ejemplo, IVector<T>.SetAt([in] UInt32 index, [in] T value)).

Los terceros no pueden definir nuevas interfaces parametrizadas. Solo se admiten las interfaces parametrizadas definidas por el sistema.

Delegados

Un delegado es un tipo winRT que actúa como puntero de función segura para tipos. Un delegado es básicamente un objeto WinRT simple que expone una única interfaz que hereda de IUnknown y define un único método denominado Invoke. Al invocar el delegado a su vez, se invoca el método al que hace referencia. Los delegados suelen usarse (pero no exclusivamente) para definir eventos de WinRT.

Un delegado de WinRT es un tipo con nombre y define una firma de método. Las firmas de método delegado siguen las mismas reglas para los parámetros que los métodos de interfaz. Los nombres de firma y parámetro del método Invoke deben coincidir con la definición del delegado.

Al igual que las interfaces, los delegados no parametrizados deben tener un identificador de interfaz único (también conocido como IID) especificado a través de guidAttribute. El IID del delegado se usa como IID de la interfaz de método única que se usa para implementar el delegado. Los delegados con parámetros deben tener un identificador de interfaz con parámetros único (también conocido como PIID) especificado a través de guidAttribute. El PIID se usa para generar un IID para una instancia de delegado con parámetros específica a través del algoritmo especificado anteriormente.

Un delegado debe tener visibilidad pública.

IUnknown

Tenga en cuenta que, a diferencia de las interfaces de WinRT, los delegados implementan IUnknown, pero no IInspectable. Esto significa que no se pueden inspeccionar para obtener información de tipo en tiempo de ejecución.

Delegados con parámetros

Los delegados admiten la parametrización de tipos. Una definición de delegado parametrizada especifica una lista de parámetros de tipo además de la firma del método tradicional como se especificó anteriormente. En la firma del método, cualquier parámetro se puede especificar como uno de los tipos de la lista de argumentos de tipo de delegados con parámetros.

Los terceros no pueden definir nuevos delegados con parámetros. Solo se admiten los delegados parametrizados definidos por el sistema.

Miembros de interfaz

Las interfaces de WinRT admiten tres tipos de miembros: métodos, propiedades y eventos. Es posible que las interfaces no tengan campos de datos.

Métodos

Las interfaces de WinRT admiten métodos que toman cero o más parámetros y que devuelven un HRESULT que indica el éxito o error de la llamada al método. Opcionalmente, un método puede indicar un parámetro de salida único que se va a proyectar como el valor devuelto en lenguajes basados en excepciones. Este parámetro de salida de valor devuelto, si se especifica, debe ser el último parámetro de la firma del método.

Un método debe tener visibilidad pública.

Es posible que un método no use números variables de argumentos. Es posible que un método no tenga parámetros opcionales ni parámetros con valores predeterminados.

Es posible que un método no esté parametrizado. Los delegados y métodos parametrizados de las interfaces con parámetros pueden usar parámetros de tipo del tipo contenedor en la firma del método.

Parámetros

Todos los parámetros de método excepto los parámetros de longitud de matriz (descritos a continuación) deben tener un nombre y un tipo. Tenga en cuenta que los valores devueltos deben especificar un nombre igual que los parámetros. Los nombres de parámetros de método, incluido el nombre del tipo de valor devuelto, deben ser únicos dentro del ámbito del método.

Solo los parámetros para delegados con parámetros y los miembros de interfaces con parámetros pueden especificar un tipo parametrizado para el tipo de parámetro. Es posible que los métodos no se parametricen individualmente. Los parámetros siempre pueden especificar instancias de tipo con parámetros (por ejemplo, IVector<int>) como tipo de parámetro.

Todos los parámetros de método deben estar exclusivamente dentro o fuera de los parámetros. No se admiten parámetros de in/out.

Aunque un método en una interfaz winRT debe devolver un HRESULT, un método puede indicar opcionalmente que su parámetro de salida final está pensado para usarse como valor devuelto cuando el método se proyecta en lenguajes basados en excepciones. Estos parámetros se conocen como parámetros [out, retval] después de la sintaxis MIDL usada para declararlos. Cuando se especifica un parámetro [out, retval], debe ser el último parámetro de la firma del método.

Aparte de [out, retval] que necesitan aparecer al final de la lista de parámetros, no hay otros requisitos de ordenación para los parámetros out.

Parámetros de matriz

Los métodos winRT admiten parámetros de matriz conformes. Las matrices nunca se pueden usar excepto como parámetros. No pueden ser tipos con nombre independientes y no se pueden usar como un tipo de campo de estructura. Los parámetros de matriz se pueden usar como inparámetros , outy retval .

WinRT admite parámetros de matriz de la mayoría de los tipos de WinRT, incluidos los tipos fundamentales (incluidos string y guid), structs, enumeraciones, delegados, interfaces y clases en tiempo de ejecución. No se permiten matrices de otras matrices.

Dado que son conformes, los parámetros de matriz siempre deben ir precedidos inmediatamente en la lista de parámetros por un parámetro para el tamaño de la matriz. El parámetro de tamaño de matriz debe ser UInt32. El parámetro de tamaño de matriz no tiene un nombre.

WinRT admite tres estilos de paso de matriz diferentes.

  • PassArray. Este estilo se usa cuando el llamador proporciona una matriz al método . En este estilo, tanto el parámetro de tamaño de matriz como el parámetro de matriz son ambos in parámetros.
  • FillArray. Este estilo se usa cuando el llamador proporciona una matriz para que el método se rellene, hasta un tamaño máximo de matriz. En este estilo, el parámetro de tamaño de matriz es un in parámetro, mientras que el parámetro de matriz es un out parámetro. Cuando se usa el estilo FillArray, el parámetro de matriz puede especificar opcionalmente uno de los otros parámetros como parámetro de longitud de matriz. Puede ver los detalles a continuación.
  • ReceiveArray. Este estilo se usa cuando el autor de la llamada recibe una matriz asignada por el método . En este estilo, el parámetro de tamaño de matriz y el parámetro de matriz son ambos out parámetros. Además, el parámetro de matriz se pasa por referencia (es decir, ArrayType**, en lugar de ArrayType*).

Nota:

La combinación de un out parámetro de tamaño de matriz, pero un in parámetro de matriz, no es válido en WinRT.

Cuando se usa un parámetro de matriz como parámetro [out, retval], el parámetro de longitud de matriz debe ser un out parámetro, es decir, solo el estilo ReceiveArray es legal para retval las matrices.

Parámetro de longitud de matriz

Un parámetro de matriz de estilo FillArray puede especificar opcionalmente otro parámetro como parámetro de longitud de matriz. Cuando el parámetro de tamaño de matriz requerido especifica el número máximo de elementos de una matriz proporcionada por el autor de la llamada, el parámetro de longitud de la matriz especifica el número de elementos rellenados realmente por el destinatario.

El parámetro de longitud de matriz se especifica con el atributo LengthIs en el parámetro de matriz.

Sobrecarga de métodos

Dentro del ámbito de una sola interfaz, es posible que más de un método tenga el mismo nombre. Los métodos con el mismo nombre en una interfaz deben tener firmas únicas. Las propiedades y los eventos no se pueden sobrecargar.

WinRT admite la sobrecarga en los tipos de parámetros, pero favorece la sobrecarga en el número de parámetros de entrada, también conocido como aridad del método. Esto se hace para admitir lenguajes dinámicos y de tipo débil (como JavaScript).

Cuando una interfaz tiene varios métodos del mismo nombre y número de parámetros de entrada, exactamente uno de esos métodos debe marcarse como predeterminado. De todos los métodos sobrecargados con el mismo nombre y número de parámetros de entrada, solo el método marcado como predeterminado se proyectará mediante un lenguaje dinámico y débilmente tipado. Si solo hay un único método sobrecargado de un nombre determinado y un número de parámetros de entrada, marcándolo como el valor predeterminado es válido, pero no es necesario.

Para determinar la aridad de un método, los parámetros de matriz y sus parámetros de longitud necesarios se consideran un único parámetro. Los estilos PassArray y FillArray se consideran un único parámetro de entrada, mientras que el estilo ReceiveArray se considera un único parámetro de salida.

Cuando varios métodos de una interfaz tienen el mismo nombre, se debe almacenar un nombre único para cada método en colisión en un objeto OverloadAttribute asociado al método . Los métodos sobrecargados predeterminados llevan DefaultOverloadAttribute.

Sobrecarga de operadores

WinRT no admite la sobrecarga del operador. Es posible que los métodos no se llamen con los nombres de operador especiales, como op_Addition que se especifican en la especificación de la CLI de ECMA 335, partición I, sección 10.3.

Propiedades

Una propiedad es un par de métodos get/set con nombre y tipo coincidentes que aparecen en algunas proyecciones de lenguaje como campos en lugar de métodos.

Una propiedad y sus métodos get/set deben tener visibilidad pública.

Una propiedad debe tener un get método . Un método getter de propiedad no tiene parámetros y devuelve un valor del tipo de propiedad. Una propiedad con solo un get método se denomina propiedad de solo lectura.

Opcionalmente, una propiedad puede tener un set método . Un método establecedor de propiedades tiene un único parámetro del tipo de propiedad y devuelve void. Una propiedad con un get método y set se denomina propiedad de lectura y escritura.

Es posible que las propiedades no se parametricen. Las propiedades de las interfaces con parámetros pueden usar parámetros de tipo del tipo contenedor como tipo de propiedad.

Eventos

Un evento es un par de métodos de agente de escucha add/remove con el nombre coincidente y el tipo de delegado. Los eventos son un mecanismo para que la interfaz notifique a las partes interesadas cuando ocurre algo importante.

Un evento y sus métodos de agente de escucha add/remove deben tener visibilidad pública.

Un método de escucha de eventos add tiene un único parámetro del tipo de delegado de eventos y devuelve un Windows. Foundation.EventRegistrationToken. Un método de escucha de eventos remove tiene un único parámetro del Windows. El tipo Foundation.EventRegistrationToken y devuelve void.

Es posible que los eventos no se parametricen. Los eventos de interfaces con parámetros pueden usar parámetros de tipo del tipo contenedor como tipo delegado de eventos.

Clases en tiempo de ejecución

WinRT te permite definir una clase. Una clase debe implementar una o varias interfaces. Una clase no puede implementar miembros de tipo directamente (es decir, no puede definir sus propios métodos, propiedades ni eventos). Una clase debe proporcionar una implementación de todos los miembros de todas las interfaces que implementa.

Hay varios tipos diferentes de interfaces, que se describen en detalle a continuación.

  • Interfaces miembro (incluidas las interfaces protegidas y reemplazables)
  • Interfaces estáticas
  • Interfaces de generador de activación
  • Interfaces de fábrica de composición

Las clases en tiempo de ejecución no se pueden parametrizar. Una clase en tiempo de ejecución puede implementar una instancia de interfaz parametrizada (es decir, una interfaz con parámetros con todos sus parámetros de tipo especificados) en cualquier lugar en el que normalmente aceptaría una interfaz no parametrizada.

Una clase en tiempo de ejecución debe tener visibilidad pública.

Una clase en tiempo de ejecución solo puede implementar interfaces que no son exclusivas (es decir, no llevan el atributo exclusiveTo) o que son exclusivas de la clase en tiempo de ejecución en cuestión. Es posible que una clase en tiempo de ejecución no implemente interfaces exclusivas de una clase en tiempo de ejecución diferente. Hay una excepción a esta regla: una clase que se puede componer puede implementar interfaces exclusivas de una clase en su cadena de derivación marcada como reemplazable. Detalles sobre las interfaces reemplazables que se deben seguir.

Interfaz de miembro

Una clase en tiempo de ejecución puede implementar cero o más interfaces miembro. Las interfaces miembro permiten que las clases expongan la funcionalidad asociada a instancias de la clase . Una clase en tiempo de ejecución especifica una lista de las interfaces miembro que implementa. Las entradas de la lista de interfaces miembro implementadas por una clase en tiempo de ejecución pueden llevar opcionalmente información de versión. Detalles sobre el control de versiones de la clase en tiempo de ejecución que se debe seguir.

Las interfaces miembro se implementan directamente en instancias de la clase en tiempo de ejecución.

Las clases en tiempo de ejecución que implementan una o varias interfaces miembro deben especificar una de las interfaces miembro para que sean la interfaz predeterminada. Las clases en tiempo de ejecución que implementan interfaces miembro cero no especifican una interfaz predeterminada.

Interfaces estáticas

Las clases de WinRT pueden especificar cero o más interfaces estáticas. Las interfaces estáticas permiten a las clases exponer la funcionalidad asociada a la propia clase, en lugar de con instancias específicas de la clase.

Una clase debe especificar al menos un miembro o una interfaz estática. Una clase sin miembro y ninguna interfaz estática no es válida.

Las interfaces estáticas se especifican a través de staticAttribute asociada a la clase en tiempo de ejecución. StaticAttribute incluye una referencia a la referencia de la interfaz estática, así como la información de versión. Detalles sobre el control de versiones de la clase en tiempo de ejecución que se debe seguir.

Aunque las interfaces estáticas se declaran como parte de la clase en tiempo de ejecución, en realidad no se implementan en las propias instancias de clase. En su lugar, se implementan en el generador de activación de la clase. Detalles sobre las factorías de activación que se deben seguir.

Activación

Opcionalmente, las clases en tiempo de ejecución admiten la activación: la capacidad del sistema para generar instancias de una clase especificada. Las clases deben implementar al menos una interfaz miembro para admitir la activación.

WinRT define tres mecanismos de activación: activación directa (sin parámetros de constructor), activación de fábrica (con uno o más parámetros de constructor) y activación de composición. Las clases no redactables pueden admitir la activación directa o de fábrica. Las clases que se pueden componer solo admiten la activación que se puede crear. Detalles sobre la composición y la activación que se pueden componer que se deben seguir.

Las clases que admiten la activación directa se activan mediante una llamada al método IActivationFactory.ActivateInstance en el generador de activación de la clase. Este método no toma parámetros y devuelve una instancia recién activada de la clase en tiempo de ejecución. Detalles sobre las factorías de activación que se deben seguir.

Las clases que admiten la activación de fábrica definen una o varias interfaces de fábrica, que a su vez definen uno o varios métodos de fábrica. Estas interfaces de fábrica se implementan en el generador de activación de la clase.

Los métodos de fábrica toman uno o varios in parámetros y deben devolver una instancia recién activada de la clase en tiempo de ejecución. No se permiten otros out parámetros más allá de la instancia de clase recién activada. Los métodos de fábrica deben tomar uno o varios parámetros: no se permite la activación de fábrica sin parámetros. La activación directa debe usarse para la activación sin parámetros.

Las clases que admiten la activación directa o de fábrica se marcan con ActivationableAttribute. ActivationableAttribute incluye información de versión (detalles sobre el control de versiones de la clase en tiempo de ejecución que se debe seguir), así como una referencia opcional a la interfaz de fábrica. Las clases se pueden marcar con varios ActivationableAttributes, como máximo uno para la activación predeterminada, más uno para cada interfaz de fábrica implementada por el generador de activación de la clase. Es posible que las clases marcadas con ActiveableAttribute no se marquen también con ComposableAttribute. Detalles sobre la composición que se va a seguir.

Composición

Opcionalmente, las clases en tiempo de ejecución admiten la composición: la capacidad de combinar varias instancias de clase en lo que parece ser un solo objeto desde el exterior. WinRT usa la composición como una forma de herencia de clases en tiempo de ejecución.

Opcionalmente, las clases de WinRT pueden componer una sola clase base composable, que a su vez puede componer una sola clase base que se pueda componer, etc. No es necesario que una clase se pueda componer para crear una clase base que se pueda componer. Las clases solo se pueden componer con una clase que se puede componer como una clase base. No se requiere una clase que se pueda componer para crear otra clase que se pueda componer (es decir, puede ser la raíz de la jerarquía). No se permiten gráficos circulares de composición (como A composes B, que componen A).

En tiempo de ejecución, una clase de redacción es una agregación de objetos WinRT, una para cada objeto de la cadena de composición. Estos objetos agregados delegan la identidad y la duración en el objeto activado originalmente en la cadena de composición (denominado objeto de control). Cada objeto de la cadena contiene un puntero IInspectable no delegado a la clase que compone para llamar a métodos en interfaces de clase base compuestas, incluidos los métodos en interfaces protegidas. Cada objeto de la cadena tiene un puntero a la clase de control para delegar la duración y la identidad, así como para llamar a métodos en interfaces reemplazables. Detalles sobre las interfaces protegidas y reemplazables que se deben seguir.

Vamos a tomar el ejemplo de que Button compone control, que a su vez compone UIElement. En ese ejemplo, una instancia de Button agrega una instancia de Control , que a su vez agrega una instancia uiElement . Los tres objetos tienen una referencia al objeto Button para controlar la duración y la identidad, así como para consultar las interfaces reemplazables. Cada objeto tiene un puntero IInspectable al objeto que compone (Button contiene un puntero a Control; El control contiene un puntero a UIElement) para poder llamar a métodos en interfaces implementadas en clases compuestas, incluidas interfaces protegidas.

Una clase no puede implementar ninguna interfaz definida en la clase que redacta, ni ninguna clase de la cadena de composición, a menos que la interfaz se marque como reemplazable en la clase composable. Detalles sobre las interfaces reemplazables que se deben seguir.

Una clase composable debe marcarse con uno o varios ComposableAttributes. ComposableAttribute lleva una referencia a la interfaz de fábrica de composición, tanto si los métodos de fábrica de la interfaz de fábrica de composición se pueden usar para controlar la activación de objetos o no, así como la información de versión. Detalles sobre las interfaces de fábrica de composición y el control de versiones que se deben seguir. Una clase se puede marcar con varios composableAttributes, uno para cada interfaz de generador de composición implementada por el generador de activación de la clase.

La proyección del lenguaje JavaScript no admite la composición de clases. Por lo tanto, las clases que se pueden componer y las clases que se pueden componer deben marcarse con WebHostHiddenAttribute que indica que JavaScript no debe intentar proyectar estos tipos.

Los terceros solo pueden definir clases que componen otras clases que se pueden componer. Es posible que no defina su propia clase raíz que se pueda crear.

Activación que se puede componer

Una clase composable debe definir una o varias interfaces de generador de composición, que a su vez implementan uno o varios métodos de factoría de composición. Las interfaces de factoría de composición se implementan en el generador de activación de la clase. Detalles sobre las factorías de activación que se deben seguir.

Se usa una interfaz de generador de composición para crear instancias que se pueden componer de la clase . Una interfaz de fábrica compuesta declara cero o más métodos de fábrica que se pueden usar para activar instancias de la clase con fines de composición. Tenga en cuenta que es legal tener una interfaz de fábrica compuesta con cero métodos de fábrica. Esto implica que la clase se puede usar para la composición, pero que los terceros no pueden componer directamente la clase, los métodos para crear instancias son solo internos.

Una clase composable declara si los métodos de fábrica de una interfaz de fábrica de composición determinada se pueden usar para activar la clase directamente como un objeto de control o no. Las interfaces de fábrica compuestas marcadas como públicas se pueden usar para activar directamente una clase como un objeto de control, así como indirectamente para activar una clase como un objeto compuesto. Las interfaces de fábrica compuestas marcadas como protegidas solo se pueden usar para activar indirectamente una clase como un objeto compuesto. Las clases composables siempre se pueden activar como objetos compuestos.

Una interfaz de generador de composición debe ser exclusiveto la clase en tiempo de ejecución que implementa.

Al igual que un método de generador de activación, un método de factoría de composición debe devolver una instancia de la clase composable. Además, un método de generador de composición tiene dos parámetros adicionales: el parámetro IInspectable* [in] de control y el parámetro IInspectable** [out] no delegating. Opcionalmente, un método de generador de composición puede tener parámetros adicionales in . Si se especifica, se deben producir los parámetros adicionales en el principio de la firma del método, antes de que los parámetros obligatorios aparezcan anteriormente. Es posible que un método de generador de composición no tenga parámetros adicionales out más allá de IInspectable** y los parámetros de valor devuelto.

Cuando se activa una clase composable para la composición (por ejemplo, Control o UIElement cuando se activa una instancia de Button ), se pasa un puntero al objeto que controla la identidad y la duración a través del parámetro IInspectable* [in]. El método de fábrica composable devuelve la instancia recién activada como el valor devuelto. Esta instancia delega toda la funcionalidad de administración de identidades y duración en el control IInspectable* proporcionado. Además, el método de fábrica composable devuelve un puntero a un IInspectable no delegable* que la clase de composición puede usar para invocar métodos en una clase compuesta.

Cuando se activa una clase composable como una clase de control (por ejemplo, Button en el ejemplo anterior), se usan los mismos métodos de generador que se pueden componer que para la activación para la composición. Al activar directamente una clase composable, se pasa null para el parámetro *IInspectable* de control. Se trata de un indicador de la clase composable que se está activando como una clase de control. Cuando una clase de control crea la instancia de la clase que compone, pasa una referencia a sí misma como parámetro IInspectable* de control. El método de fábrica composable devuelve la instancia de clase de control como valor devuelto. El código de cliente omite el parámetro IInspectable** [out] no delegating al activar una clase que controle la composición.

Basándose en el ejemplo anterior Button ->Control ->UIElement , la clase de botón se activaría llamando a uno de sus métodos de generador de composición y pasando null para el parámetro externo. A su vez, el botón activaría una instancia de Control, pasando una referencia a sí misma como parámetro externo. A su vez, el control activaría una instancia de UIElement , pasando la referencia externa que recibió como parámetro externo. El método de fábrica UIElement volvería a Controlar el UIElement recién creado en el parámetro de instancia, así como una referencia a la IInspectable no delegable de UIElement en el parámetro interno. El método Generador de controles devolvería a Button el control recién creado en el parámetro de instancia, así como una referencia a IInspectable no delegante de Control en el parámetro interno. El generador de composición button volvería al código de llamada el Botón recién creado en el parámetro de instancia y null para el parámetro interno.

Es posible que una clase se active a veces para la composición y otras veces se active como la clase de control. Por ejemplo, si Botón compuesto por RadioButton, se activaría Button para la composición cuando se activaba un RadioButton; pero se activa como la clase de control cuando Button se activó directamente. En cualquier caso, la clase Control que Botón compone se activaría para la composición.

Interfaces protegidas

Una clase composable puede declarar cero o más de sus interfaces miembro que se van a proteger. Es posible que una clase no composable no declare interfaces miembro que se van a proteger. Solo el código de una clase que compone una clase que se puede componer (directa o indirectamente) puede consultar y usar interfaces que la clase composable declara como protegida. Es posible que el código de fuera de la cadena de composición no consulte ni use interfaces que la clase composable declara como protegida.

Por ejemplo, si UIElement declara una interfaz protegida IUIElementProtected, solo las clases que componen UIElement ,incluida la composición directa (Control) e indirecta (Button), pueden consultar y usar la interfaz IUIElementProtected .

Interfaces reemplazables

Una clase composable puede declarar cero o más de sus interfaces miembro que se van a invalidar. Una interfaz reemplazable solo se puede consultar y usar dentro de una cadena de composición, similar a las reglas sobre el acceso a interfaces protegidas detalladas anteriormente. Sin embargo, cuando la clase que lo declaró originalmente solo puede implementar una interfaz protegida, las interfaces reemplazables pueden volver a implementarse mediante clases que componen la clase que implementó la interfaz reemplazable.

En tiempo de ejecución, cualquier código de clase composable que aproveche la interfaz reemplazable debe consultarInterface para la interfaz a través del puntero IInspectable* de control que se usa para la delegación de identidad y duración. Este puntero devuelve la implementación de la interfaz reemplazable más antigua de la cadena de composición (es decir, más cercana a la instancia de clase de control). Una clase que desee tener acceso a las interfaces reemplazables de la clase que redacta puede hacerlo a través de la referencia no de delegación que contiene una clase composable en su clase compuesta.

Vamos a tomar el ejemplo de que UIElement declara una interfaz reemplazable IUIElementOverridable. En ese caso, las clases que derivan de UIElement, incluida la derivación directa (Control) y indirecta (Button), se les permitiría implementarla. Si el código de UIElement necesitaba tener acceso a la funcionalidad en IUIElementOverridable, UIElement consultaría el control IInspectable para obtener la implementación más antigua en la cadena de composición. Si control y botón implementaron IUIElementOverridable, se devolverá la implementación de Button cuando se consultara la IInspectable de control. Si Button quiere acceder a su funcionalidad de clase compuesta, puede usar la IInspectable no delegable que se devolvió desde el método de generador de composición para consultar la clase base de esa interfaz.

Generadores de activación

Opcionalmente, una clase en tiempo de ejecución tiene un generador de activación. Una clase en tiempo de ejecución debe tener un generador de activación si la clase es activable, composable o tiene interfaces estáticas. El generador de activación de una clase se puede recuperar del sistema en tiempo de ejecución a través de la función Win32 RoGetActivationFactory .

Las factorías de activación deben implementar la interfaz IActivationFactory . Sin embargo, solo las clases que admiten la activación directa proporcionan una implementación del método único ActivateInstance de IActivationFactory. Las clases que no admiten la activación directa deben devolver E_NOTIMPL desde IActivationFactory.ActivateInstance.

La factoría de activación debe implementar todas las interfaces de factoría de activación, las interfaces de fábrica de composición y las interfaces estáticas definidas en la clase en tiempo de ejecución.

No hay ninguna garantía de que las proyecciones de lenguaje mantengan una única instancia de generador de activación durante la vigencia de la fábrica. Los autores de clases de WinRT que necesitan guardar información de larga duración para el acceso a miembros estáticos necesitan almacenarla en algún lugar fuera del generador de activación.

Proyección basada en clases

Aunque WinRT es principalmente un modelo de programación basado en interfaz en segundo plano, las clases en tiempo de ejecución proporcionan un modelo de programación basado en clases que está mejor alineado con lenguajes de programación modernos, estándar y orientados a objetos (OO). Se espera que las proyecciones de lenguaje proyectan una clase en tiempo de ejecución como una sola entidad, en lugar de como un contenedor de interfaces con las que el desarrollador tiene que tratar por separado.

Para lograr este modelo basado en clases, se espera que las proyecciones de lenguaje proyectan miembros de tipo desde interfaces miembro de una clase como miembros de clase directos. Se espera que las proyecciones de lenguaje projecte miembros del tipo de las interfaces estáticas de una clase como miembros de clase estática. Por último, se espera que las proyecciones de lenguaje proyectan métodos de activación (activación directa, así como interfaces de fábrica de fábrica y de composición) como constructores de clase.

Para ayudar en esta proyección basada en clases en tiempo de ejecución, los metadatos de las clases en tiempo de ejecución especifican un miembro de clase para todos los métodos, propiedades y eventos de cada interfaz que implementan. Cada miembro de clase se vincula explícitamente al miembro de interfaz donde se definió originalmente. Esto permite que las proyecciones de lenguaje expongan la clase como una sola entidad, controlando todas las consultas de interfaz y recuento de referencias en segundo plano en nombre del desarrollador.

De forma predeterminada, cada miembro de interfaz implementado se proyecta como miembro de clase. Sin embargo, dado que las clases en tiempo de ejecución pueden implementar varias interfaces independientes y versiones a lo largo del tiempo (detalles de control de versiones que se deben seguir), es posible que haya colisiones de nombres para los miembros definidos en diferentes interfaces implementadas por una sola clase en tiempo de ejecución.

Cuando se producen colisiones, la proyección de miembro de clase predeterminada es imposible. Si se producen colisiones entre interfaces agregadas en versiones independientes, el miembro en conflicto de la versión más antigua se proyecta como miembro de clase. Cuando se producen colisiones entre interfaces agregadas en la misma versión, ninguno de los miembros colisionados se proyecta como miembros de clase. Tenga en cuenta que los métodos con nombres en colisión se permiten siempre y cuando todas las versiones sean de aridad diferente, como se describe en Sobrecarga de métodos.

Los miembros de interfaz que no están proyectados como miembros de clase deben estar disponibles para los desarrolladores. Normalmente, esto se realiza mediante un operador de búsqueda dinámica o de conversión, lo que permite al desarrollador especificar la interfaz y el método específicos que quieren invocar.

Para resolver colisiones de nombres de método, las clases en tiempo de ejecución pueden especificar nombres alternativos para los métodos en las interfaces estáticas y miembro que implementan. La proyección de lenguaje usa este nombre alternativo para proporcionar acceso desambiguado a los nombres de método en colisión de una instancia de clase. Aunque la clase en tiempo de ejecución puede proporcionar un nombre de método alternativo, la firma del método, los parámetros y los atributos adjuntos al método o sus atributos deben coincidir exactamente con la definición de interfaz original.

Dado que la activación directa, los métodos de fábrica y los métodos de fábrica de composición se proyectan como constructores de clase, todos se proyectan en la clase en tiempo de ejecución como si tuvieran el mismo nombre. Todos los métodos de todas las interfaces de fábrica deben tener firmas únicas, deben favorecer la sobrecarga basada en la aridad sobre la sobrecarga basada en tipos y deben usar DefaultOverloadAttribute para desambiguar los métodos de fábrica de la misma aridad.

Control de versiones de clase

Las clases en tiempo de ejecución son compatibles con versiones adicionales. Las versiones posteriores de una clase en tiempo de ejecución determinada pueden especificar interfaces adicionales de todos los tipos, con más detalles sobre los tipos de interfaz individuales siguientes. Es posible que las interfaces preexistentes especificadas por una clase nunca se quiten o cambien sin interrumpir la compatibilidad con versiones anteriores.

Control de versiones de interfaz de miembro

Las interfaces miembro de las clases en tiempo de ejecución son compatibles con versiones adicionales. Las versiones posteriores de una clase en tiempo de ejecución determinada pueden implementar interfaces de miembro adicionales, incluso si la clase nunca había implementado interfaces miembro anteriormente. Las versiones posteriores de una clase en tiempo de ejecución compuesta determinada pueden implementar interfaces protegidas e invalidables adicionales.

Las interfaces implementadas por una clase en tiempo de ejecución llevan opcionalmente VersionAttribute para distinguir cuándo se agregaron interfaces específicas al tipo de clase en tiempo de ejecución. Los valores de implementación de interfaz sin versionAttribute se consideran tener el mismo valor de versión que el tipo de clase en tiempo de ejecución envolvente.

Control de versiones de interfaz estática

Las interfaces estáticas en las clases en tiempo de ejecución son compatibles con versiones adicionales. Las versiones posteriores de una clase en tiempo de ejecución determinada pueden implementar interfaces estáticas adicionales, incluso si la clase nunca había implementado interfaces estáticas anteriormente.

StaticAttribute incluye un parámetro UInt32 para el número de versión, que define la versión de Windows que agregó esa compatibilidad con la activación.

Control de versiones de activación

La compatibilidad con la activación para clases en tiempo de ejecución es compatible con versiones adicionales. Las versiones posteriores de una clase en tiempo de ejecución determinada pueden implementar mecanismos de activación adicionales, incluso si la clase nunca había implementado un mecanismo de activación. Tenga en cuenta que las clases composables no se pueden activar y, por tanto, es posible que no agreguen compatibilidad con la activación.

Tenga en cuenta que una clase que admite la activación directa solo puede agregar nuevas interfaces de activación de fábrica. Una clase que anteriormente solo admitía la activación de fábrica puede agregar compatibilidad con la activación directa, así como nuevas interfaces de activación de fábrica.

El elemento ActivatableAttribute incluye un parámetro UInt32 para el número de versión. El número de versión de ActivationableAttribute define la versión de Windows que agregó esa compatibilidad con la activación.

Control de versiones de composición

La compatibilidad de composición con clases en tiempo de ejecución es compatible con versiones adicionales. Las versiones posteriores de una clase en tiempo de ejecución compuesta determinada pueden implementar mecanismos de composición adicionales, siempre que la clase se haya definido como composable cuando se creó. Es posible que las clases compuestas no agreguen compatibilidad con la activación.

ComposableAttribute incluye un parámetro UInt32 para el número de versión. El número de versión de ComposableAttribute define la versión de Windows que agregó esa compatibilidad con la composición.

Atributos personalizados

WinRT admite la definición de atributos de metadatos personalizados. Todas las construcciones del sistema de tipos winRT pueden llevar atributos de metadatos personalizados. Esto incluye todos los tipos con nombre (enumeraciones, estructuras, delegados, interfaces, clases, etc.), así como elementos individuales contenidos en construcciones de tipo (como métodos, parámetros, etc.).

Los atributos personalizados se denominan como otros tipos de WinRT. Sin embargo, no se pueden activar. Son puramente una construcción de datos.

Los atributos personalizados definen un esquema de datos de parámetros posicionales o campos con nombre. Un atributo personalizado puede no usar los parámetros posicionales y los campos con nombre, sino que debe elegir uno u otro. Los tipos de parámetros y campos de un atributo personalizado se limitan a los tipos fundamentales, enumeraciones y referencias de WinRT a otros tipos de WinRT. No se permite ningún otro parámetro o tipo de campo.

Los atributos personalizados que usan parámetros posicionales deben definir uno o varios conjuntos válidos de parámetros posicionales. Cada conjunto debe especificar cero o más parámetros posicionales. Una instancia del atributo personalizado debe especificar un único conjunto de parámetros posicionales, así como datos para cada parámetro posicional del conjunto seleccionado.

Un atributo personalizado que usa campos con nombre especifica cero campos con nombres y tipos. Una instancia del atributo personalizado debe especificar los pares nombre-valor para los campos que desea especificar. Una instancia puede especificar valores para todos, algunos o ninguno de los pares nombre-valor.

Es válido para que un atributo no tenga parámetros posicionales ni campos con nombre.

Un atributo personalizado debe tener visibilidad pública.

Un atributo puede especificar los tipos de construcciones de tipo WinRT con las que se puede asociar a través de AttributeUsageAttribute.

Los terceros no pueden definir atributos personalizados. Solo se admiten los atributos personalizados definidos por el sistema.