Valores de boxing e unboxing para IInspectable com C++/WinRT

Note

Você pode encapsular e desempacotar não apenas valores escalares, mas também a maioria dos tipos de arrays (com exceção de arrays de tipos enumerados) por meio das funções winrt::box_value e winrt::unbox_value. Você pode desempacotar apenas valores escalares usando a função winrt::unbox_value_or.

A interface IInspectable é a interface raiz de cada classe de runtime no WinRT (Windows Runtime). Essa é uma ideia análoga ao IUnknown estar na raiz de cada interface e classe COM; e System.Object sendo a raiz de cada classe Common Type System .

Em outras palavras, uma função que espera um IInspectable pode receber uma instância de qualquer classe de tempo de execução. Mas você não pode passar diretamente para essa função um valor escalar (como um valor numérico ou de texto), nem uma matriz. Em vez disso, um valor escalar ou de matriz precisa ser encapsulado dentro de um objeto de classe de referência. Esse processo de encapsulamento é conhecido como boxing do valor.

Important

Você pode empacotar e desempacotar qualquer tipo que você possa passar para uma API do Windows Runtime. Em outras palavras, um tipo de Windows Runtime. Valores numéricos e de texto (cadeias de caracteres) e matrizes são alguns exemplos fornecidos acima. Outro exemplo é um struct que você define no IDL. Se você tentar encaixotar um struct C++ comum (isto é, que não está definido em IDL), o compilador informará que você só pode encaixotar um tipo do Windows Runtime. Uma classe de runtime é um tipo do Windows Runtime, mas você pode, é claro, passar classes de runtime para APIs do Windows Runtime sem empacotá-las.

O C++/WinRT fornece a função winrt::box_value, que recebe um valor escalar ou de matriz e retorna o valor encapsulado em um IInspectable. Para desempacotar um IInspectable de volta em um valor escalar ou vetor, existe a função winrt::unbox_value. Para desempacotar um IInspectable novamente em um valor escalar, há também a função winrt::unbox_value_or.

Exemplos de empacotamento de valor

A função do acessador LaunchActivatedEventArgs::Arguments retorna um winrt::hstring, que é um valor escalar. Podemos encapsular esse valor hstring e passá-lo para uma função que espera IInspectable assim.

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

Para definir a propriedade de conteúdo de um Botão XAML, você chama a função de mutador Button::Content . Para definir a propriedade de conteúdo como um valor de cadeia de caracteres, você pode usar esse código.

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

Primeiro, o construtor de conversão hstring converte o literal da cadeia de caracteres em um hstring. Em seguida, a sobrecarga de winrt::box_value que usa um hstring é invocada.

Exemplos de como fazer unboxing de um IInspectable

Em suas próprias funções que esperam IInspectable, você pode usar winrt::unbox_value para desempacotar, e também pode usar winrt::unbox_value_or para desempacotar com um valor padrão. Você também pode usar try_as para fazer o unboxing para um 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.
}

Determinar o tipo de um valor encapsulado

Se você receber um valor encapsulado e não tiver certeza de que tipo ele contém (você precisa saber o tipo para desencapsulá-lo), poderá consultar a interface IPropertyValue do valor encapsulado e, em seguida, chamar Type nessa interface. Aqui está um exemplo de código.

WINRT_ASSERT é uma definição de macro e se expande para _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);

APIs importantes