Boxing et unboxing de valeurs vers IInspectable avec C++/WinRT

Notes

Vous pouvez effectuer une conversion boxing et unboxing aussi bien de valeurs scalaires que de la plupart des types de tableaux (à l’exception des tableaux d’énumérations) en utilisant les fonctions winrt::box_value et winrt::unbox_value. Vous pouvez effectuer une conversion unboxing seulement des valeurs scalaires en utilisant la fonction winrt::unbox_value_or.

L’interface IInspectable est l’interface racine de chaque classe runtime dans Windows Runtime (WinRT). Il s’agit d’un concept analogue à IUnknown se trouvant à la racine de chaque interface et classe COM et de System.Object se trouvant à la racine de chaque classe Common Type System.

En d’autres termes, une fonction qui attend IInspectable peut se voir transmettre une instance de n’importe quelle classe runtime. Mais vous ne pouvez pas transmettre directement une valeur scalaire à cette fonction (comme une valeur numérique ou une valeur texte), ni un tableau. Au lieu de cela, une valeur scalaire ou tabulaire doit être encapsulée dans un objet de classe de référence. Ce processus d’encapsulation est appelé boxing de la valeur.

Important

Vous pouvez convertir (boxing et unboxing) tout type qu’il est possible de passer à une API Windows Runtime. En somme, il s’agit d’un type Windows Runtime. Les valeurs numériques et texte (chaînes), ainsi que les tableaux, correspondent à des exemples ci-dessus. Un autre exemple est un struct que vous définissez dans IDL. Si vous essayez de faire une conversion boxing d’un struct C++ standard (qui n’est pas défini dans IDL), le compilateur vous rappelle que cette conversion est possible uniquement pour un type Windows Runtime. Une classe runtime est un type Windows Runtime, mais vous pouvez bien sûr passer des classes runtime aux API Windows Runtime sans les convertir.

C++/WinRT fournit la fonction winrt::box_value, qui prend une valeur scalaire ou tabulaire et retourne la valeur convertie dans un IInspectable. Pour la conversion unboxing d’un IInspectable en une valeur scalaire ou tabulaire, il existe la fonction winrt::unbox_value. Pour la conversion unboxing d’un IInspectable en une valeur scalaire, il existe aussi la fonction winrt::unbox_value_or.

Exemples de conversion boxing d’une valeur

La fonction accesseur LaunchActivatedEventArgs::Arguments renvoie un winrt::hstring, qui est une valeur scalaire. Nous pouvons convertir cette valeur hstring et la transmettre à une fonction qui attend IInspectable comme suit.

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

Pour définir la propriété de contenu d’un élément Button XAML, appelez la fonction mutateur Button::Content. Pour définir la propriété de contenu sur une valeur de chaîne, vous pouvez utiliser ce code.

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

Tout d’abord, le constructeur de conversion hstring convertit la chaîne littérale en un hstring. Puis la surcharge de winrt::box_value qui prend un hstring est appelée.

Exemples de conversion unboxing d’un IInspectable

Dans vos propres fonctions qui attendent IInspectable, vous pouvez utiliser winrt::unbox_value pour effectuer une conversion unboxing, et vous pouvez utiliser winrt::unbox_value_or pour effectuer une conversion unboxing avec une valeur par défaut. Vous pouvez également utiliser try_as pour effectuer une conversion 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.
}

Déterminer le type d’une valeur convertie

Si vous recevez une valeur convertie et que vous n'êtes pas certain du type qu’elle contient (vous devez connaître son type pour lui appliquer une conversion unboxing), vous pouvez interroger la valeur convertie pour rechercher son interface IPropertyValue, puis appeler Type sur elle. Voici un exemple de code :

WINRT_ASSERT est une définition de macro qui s’étend à _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 importantes