Conversión boxing y unboxing de valores a IInspectable con C++/WinRT

Nota

Puede aplicar una conversión boxing y unboxing no solo a valores escalares, sino también a la mayoría de los tipos de matrices (a excepción de las matrices de enumeraciones) mediante las funciones winrt::box_value y winrt::unbox_value. Solo puede aplicar una conversión unboxing a valores escalares mediante la función winrt::unbox_value_or.

La interfaz IInspectable es la interfaz de raíz de todas las clases en tiempo de ejecución de Windows Runtime (WinRT). Esto es una idea análoga a que IUnknown se encuentra en la raíz de todas las clases e interfaces COM y a que System.Object se encuentra en la raíz de todas las clases Common Type System .

En otras palabras, una función que espera IInspectable se puede pasar a una instancia de cualquier clase en tiempo de ejecución. Sin embargo, no se puede pasar directamente a dicha función un valor escalar (como un valor numérico o de texto, a dicha función) ni una matriz. En su lugar, los valores escalares o matriciales deben encapsularse dentro de un objeto de clase de referencia. Dicho proceso de encapsulación se conoce como la conversión boxing del valor.

Importante

Puedes aplicar la conversión boxing y unboxing a cualquier tipo que puedas pasar a una API de Windows Runtime. En otras palabras, un tipo de Windows Runtime. Los valores numéricos y de texto (cadenas) y las matrices son algunos de los ejemplos indicados anteriormente. Otro ejemplo es un struct que definas en IDL. Si intentas aplicar una conversión boxing a un struct de C++ normal (uno que no se defina en IDL), el compilador te recordará que solo puedes aplicar la conversión boxing a un tipo de Windows Runtime. Una clase en tiempo de ejecución es un tipo de Windows Runtime, pero claro que puedes pasar clases en tiempo de ejecución a las API de Windows Runtime sin una conversión boxing.

C++/WinRT ofrece la función winrt::box_value, que toma un valor escalar o matricial, y devuelve el valor de conversión boxing a IInspectable. Para devolver IInspectable mediante la conversión unboxing a un valor escalar o matricial, existe la función winrt::unbox_value. Para devolver IInspectable mediante la conversión unboxing a un valor escalar, existe también la función winrt::unbox_value_or.

Ejemplos de conversión boxing de un valor

La función del descriptor de acceso LaunchActivatedEventArgs::Arguments devuelve winrt::hstring, que es un valor escalar. Podemos hacer la conversión boxing del valor hstring y pasarlo a una función que espera IInspectable de este modo.

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    ...
    rootFrame.Navigate(winrt::xaml_typename<BlankApp1::MainPage>(), winrt::box_value(e.Arguments()));
    ...
}

Para establecer la propiedad de contenido de una clase Button de XAML, llama a la función de mutación Button::Content. Para establecer la propiedad de contenido a un valor de cadena, puedes usar este código.

Button().Content(winrt::box_value(L"Clicked"));

En primer lugar, el constructor de conversión hstring convierte el literal de la cadena en un hstring. Luego, se invoca la sobrecarga de winrt::box_value que toma un hstring.

Ejemplos de conversiones unboxing de IInspectable

En tus propias funciones que esperan IInspectable, puedes usar winrt::unbox_value para realizar una conversión unboxing y winrt::unbox_value_or para realizar una conversión unboxing con un valor predeterminado. También puede usar try_as para usar una conversión unboxing en std::optional.

void Unbox(winrt::Windows::Foundation::IInspectable const& object)
{
    hstring hstringValue = unbox_value<hstring>(object); // Throws if object is not a boxed string.
    hstringValue = unbox_value_or<hstring>(object, L"Default"); // Returns L"Default" if object is not a boxed string.
    float floatValue = unbox_value_or<float>(object, 0.f); // Returns 0.0 if object is not a boxed float.
    std::optional<int> optionalInt = object.try_as<int>(); // Returns std::nullopt if object is not a boxed int.
}

Determinación del tipo de un valor de conversión boxing

Si recibes un valor de conversión boxing y no estás seguro de qué tipo contiene (necesitas conocer su tipo para aplicar la conversión unboxing), puedes consultar el valor de conversión boxing en su interfaz de IPropertyValue y, después, llamar a Type en él. Aquí tienes un ejemplo de código.

WINRT_ASSERT es una definición de macro y se expande a _ASSERTE.

float pi = 3.14f;
auto piInspectable = winrt::box_value(pi);
auto piPropertyValue = piInspectable.as<winrt::Windows::Foundation::IPropertyValue>();
WINRT_ASSERT(piPropertyValue.Type() == winrt::Windows::Foundation::PropertyType::Single);

API importantes