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