Boxing e unboxing dei valori in IInspectable con C++/WinRT

Nota

È possibile inserire e disinserire non solo valori scalari, ma anche la maggior parte degli array (ad eccezione degli array di enumerazioni) usando le funzioni winrt::box_value e winrt::unbox_value. È possibile decomprimere solo i valori scalari usando le funzioni winrt::unbox_value_or.

L'interfaccia IInspectable è l'interfaccia principale di ogni classe di runtime in Windows Runtime (WinRT). Si tratta di un concetto analogo a IUnknown alla radice di ogni classe e interfaccia COM e a System. Object alla radice di ogni classe Common Type System.

In altre parole, a una funzione che prevede IInspectable può essere passata un'istanza di una qualsiasi classe di runtime. A tale funzione non può tuttavia essere passato direttamente un valore scalare, ad esempio un valore numerico o testo, né un array. Un valore scalare o un array deve essere invece sottoposto a wrapping all'interno di un oggetto classe di riferimento. Il processo di wrapping è noto come conversione boxing del valore.

Importante

Puoi eseguire la conversione boxing e unboxing di qualsiasi tipo passabile a un'API di Windows Runtime. In altre parole, un tipo di Windows Runtime. I valori numerici e di testo (stringhe) e array sono alcuni esempi riportati in precedenza. Un altro esempio è un elemento struct definito in IDL. Se provi a eseguire la conversione boxing di un normale elemento struct C++ (non definito in IDL), il compilatore ti ricorderà che puoi eseguire il boxing solo di un tipo di Windows Runtime. Una classe di runtime è un tipo di Windows Runtime, ma naturalmente puoi passare le classi di runtime alle API di Windows Runtime senza eseguirne la conversione boxing.

C++/WinRT fornisce la funzione winrt::box_value, che accetta un valore scalare o un array e restituisce il valore sottoposto a boxing in IInspectable. Per eseguire la conversione unboxing di IInspectable in un valore scalare o un array, sono disponibili le funzioni winrt::unbox_value. Per eseguire la conversione unboxing di IInspectable in un valore scalare, sono disponibili le funzioni winrt::unbox_value.

Esempi di conversione boxing di un valore

La funzione di accesso LaunchActivatedEventArgs::Arguments restituisce winrt::hstring, ovvero un valore scalare. Possiamo sottoporre questo valore hstring a conversione boxing e passarlo a una funzione che prevede IInspectable, come di seguito.

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

Per impostare la proprietà del contenuto di un oggetto Button XAML, puoi chiamare la funzione mutatore Button::Content. Per impostare la proprietà del contenuto su un valore stringa, puoi usare questo codice.

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

In primo luogo, il costruttore di conversione hstring converte il valore letterale stringa in un valore hstring. Viene quindi richiamato l'overload di winrt::box_value che accetta un valore hstring.

Esempi di conversione unboxing di un oggetto IInspectable

Nelle funzioni che prevedono IInspectable puoi usare winrt::unbox_value per eseguire la conversione unboxing e winrt::unbox_value_or per eseguire la conversione unboxing con un valore predefinito. È possibile anche usare try_as per eseguire la conversione unboxing di 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.
}

Determina il tipo di un valore sottoposto a conversione boxing

Se ricevi un valore sottoposto a conversione boxing e non sei certo del tipo in esso contenuto (devi conoscere il relativo tipo per eseguire la conversione unboxing), puoi eseguire una query sul valore con conversione boxing per la relativa interfaccia IPropertyValue e quindi chiamare Type su di essa. Ecco un esempio di codice.

WINRT_ASSERT è una definizione di macro e si espande in 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 importanti