Boxing und Unboxing von Werten für „IInspectable“ mit C++/WinRT

Hinweis

Sie können nicht nur Skalarwerte, sondern auch die meisten Arten von Arrays (mit Ausnahme von Arrays von Enumerationen) mithilfe der Funktionen winrt::box_value und winrt::unbox_value mittels Boxing und Unboxing umwandeln. Sie können nur Skalarwerte mit der Funktion winrt::unbox_value_or mittels Unboxing umwandeln.

Die Schnittstelle „IInspectable“ ist die Stammschnittstelle jeder Laufzeitklasse in der Windows-Runtime (WinRT). Dieses Konzept kommt auch bei der Schnittstelle „IUnknown“ zur Anwendung, die sich am Stamm jeder COM-Schnittstelle und -Klasse befindet, sowie bei System.Object am Stamm jeder Klasse des allgemeinen Typsystems.

Mit anderen Worten: An eine Funktion, die IInspectable erwartet, kann eine Instanz einer beliebigen Laufzeitklasse übergeben werden. Sie können einen Skalarwert (etwa einen Zahlen- oder Textwert) einer solchen Funktion aber nicht direkt übergeben. Stattdessen müssen Skalar- oder Arraywerte innerhalb eines Referenzklassenobjekts platziert werden. Dieser Wrapping-Prozess wird als Boxing des Werts bezeichnet.

Wichtig

Du kannst jeden an eine Windows-Runtime API übergebenen Typ konvertieren (Boxing und Unboxing). Anders ausgedrückt: ein Windows-Runtime-Typ. Zahlen- und Textwerte (Zeichenfolgen) sowie Arrays sind einige der oben genannten Beispiele. Ein weiteres Beispiel ist ein struct, das du in IDL definierst. Wenn du versuchst, ein reguläres C++ struct (eines, das nicht in IDL definiert ist) per Boxing zu konvertieren, erinnert der Compiler dich daran, dass du nur einen Windows-Runtime-Typ konvertieren darfst. Eine Laufzeitklasse ist ein Windows-Runtime-Typ, aber du kannst natürlich Laufzeitklassen an Windows-Runtime-APIs übergeben, ohne sie zu per Boxing zu konvertieren.

In C++/WinRT akzeptiert die Funktion winrt::box_value einen Skalar- oder Arraywert und gibt ihn als in IInspectable geschachtelten Wert zurück. Wenn Sie ein IInspectable-Element wieder in einen Skalarwert umwandeln möchten (Unboxing), können Sie auch die Funktion winrt::unbox_value_or verwenden. Wenn Sie ein IInspectable-Element wieder in einen Skalarwert umwandeln möchten (Unboxing), können Sie auch die Funktion winrt::unbox_value_or verwenden.

Beispiele für das Boxing eines Werts

Die Accessorfunktion LaunchActivatedEventArgs::Arguments gibt eine winrt::hstring-Struktur zurück. Dabei handelt es sich um einen Skalarwert. Wir können diesen hstring-Wert mittels Boxing verpacken und an eine Funktion übergeben, die IInspectable erwartet:

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

Zum Festlegen der Inhaltseigenschaft einer XAML-Schaltfläche (Button) muss die Mutatorfunktion Button::Content aufgerufen werden. Die Inhaltseigenschaft kannst du mithilfe des folgenden Codes auf einen Zeichenfolgenwert festlegen:

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

Zuerst wandelt der hstring-Konvertierungskonstruktor das Zeichenfolgenliteral in eine hstring-Struktur um. Anschließend wird die Überladung von winrt::box_value aufgerufen, die eine hstring-Struktur akzeptiert.

Beispiele für das Unboxing von „IInspectable“

In deinen eigenen Funktionen, die IInspectable erwarten, kannst du winrt::unbox_value zum Unboxing und winrt::unbox_value_or zum Unboxing mit einem Standardwert verwenden. Sie können auch try_as zum Unboxing in ein std::optional-Element verwenden.

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.
}

Ermitteln der Art eines geschachtelten Werts

Wenn du einen geschachtelten Wert erhältst und nicht sicher bist, welchen Typ er enthält, kannst du die IPropertyValue-Schnittstelle des geschachtelten Werts abfragen und anschließend Type dafür aufrufen. (Der Typ muss bekannt sein, um das Unboxing durchführen zu können.) Hier sehen Sie ein Codebeispiel.

WINRT_ASSERT ist eine Makrodefinition, die auf _ASSERTE erweitert wird.

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

Wichtige APIs