Conversione boxing e unboxing dei valori in IInspectable con C++/WinRT

Note

È possibile impostare box e unbox non solo i valori scalari, ma anche la maggior parte dei tipi di matrici (ad eccezione delle matrici di enumerazioni) usando le funzioni winrt::box_value e winrt::unbox_value . È possibile estrarre solo valori scalari utilizzando la funzione winrt::unbox_value_or.

L'interfaccia IInspectable è l'interfaccia radice di ogni classe di runtime nella Windows Runtime (WinRT). Si tratta di un'idea analoga a IUnknown che si trova alla radice di ogni interfaccia e classe COM; e System.Object nella radice di ogni classe Common Type System .

In altre parole, una funzione che prevede IInspectable può essere passata a un'istanza di qualsiasi classe di runtime. Ma non è possibile passare direttamente a tale funzione un valore scalare (ad esempio un valore numerico o di testo) né una matrice. È invece necessario eseguire il wrapping di un valore scalare o matrice all'interno di un oggetto classe di riferimento. Questo processo di incapsulamento è noto come boxing di un valore.

Importante

Puoi eseguire il boxing e l'unboxing di qualsiasi tipo che puoi passare a un'API di Windows Runtime. In altre parole, un tipo di Windows Runtime. I valori numerici e di testo (stringhe) e le matrici sono alcuni esempi indicati in precedenza. Un altro esempio è un struct oggetto definito in IDL. Se si tenta di inserire in un box un normale C++ struct (ossia uno che non è definito in IDL), il compilatore segnalerà che è possibile inserire in un box solo un tipo Windows Runtime. Una classe di runtime è un tipo di Windows Runtime, ma ovviamente è possibile passare classi di runtime alle API di Windows Runtime senza eseguirne il boxing.

C++/WinRT fornisce la funzione winrt::box_value, che accetta un valore scalare o un array e restituisce il valore incapsulato in un oggetto IInspectable. Per estrarre un IInspectable in un valore scalare o in un array, è disponibile la funzione winrt::unbox_value. Per eseguire l'unboxing di un IInspectable in un valore scalare, è disponibile anche la funzione winrt::unbox_value_or.

Esempi di boxing di un valore

La funzione di accesso LaunchActivatedEventArgs::Arguments restituisce un valore scalare winrt::hstring. È possibile incapsulare quel valore hstring e passarlo a una funzione che si aspetta IInspectable in questo modo.

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

Per impostare la proprietà contenuto di un Button XAML, si chiama la funzione mutator Button::Content. Per impostare la proprietà content su un valore stringa, è possibile usare questo codice.

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

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

Esempi di unboxing di IInspectable

Nelle tue funzioni che accettano IInspectable, puoi usare winrt::unbox_value per estrarre il valore e puoi usare winrt::unbox_value_or per estrarre il valore usando un valore predefinito. È anche possibile utilizzare try_as per estrarre il valore come 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.
}

Determinare il tipo di un valore inscatolato

Se si riceve un valore boxed e non si è certi del tipo che contiene (è necessario conoscerne il tipo per effettuarne l'unboxing), è possibile interrogare il valore boxed per ottenere 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 fino 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 importanti