注释
通过使用 winrt::box_value 和 winrt::unbox_value 函数,不仅可以将标量值进行装箱和取消装箱,还可以对大多数类型的数组(枚举数组除外)进行装箱和取消装箱。 可以使用 winrt::unbox_value_or 函数对标量值进行取消装箱。
IInspectable 接口 是 Windows 运行时(WinRT)中每个运行时类的根接口。 这是一个类似于 IUnknown 作为每个 COM 接口和类的基础,以及 System.Object 作为每个 Common Type System 类基础的概念。
换句话说,需要 IInspectable 的函数可以传递任何运行时类的实例。 但是,不能将标量值(如数字或文本值)或数组直接传递给此类函数。 相反,需要将标量或数组值包装在引用类对象内。 这种包装过程被称为 将值 装箱。
重要
可装箱和拆箱可传递给 Windows 运行时 API 的任何类型。 换句话说,是 Windows 运行时类型。 数值和文本值(字符串)和数组是上面给出的一些示例。 另一个示例是在 IDL 中定义的 struct
。 如果尝试装箱常规C++struct
(IDL 中未定义),编译器会提醒你只能装箱 Windows 运行时类型。 运行时类是 Windows 运行时类型,但你当然可以将运行时类传递给 Windows 运行时 API,而无需装箱。
C++/WinRT 提供了 winrt::box_value 函数,该函数接收一个标量或数组值,并返回一个装箱为 IInspectable的值。 若要将 IInspectable 拆箱转换为标量或数组值,可以使用 winrt::unbox_value 函数。 若要将 IInspectable 还原为标量值,还有 winrt::unbox_value_or 函数。
装箱值的示例
LaunchActivatedEventArgs::Arguments 访问器函数返回一个 winrt::hstring,这是一种标量值。 我们可以将 hstring 值装箱,并将其传递给预期的 IInspectable 的函数,如以下所示。
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
...
rootFrame.Navigate(winrt::xaml_typename<BlankApp1::MainPage>(), winrt::box_value(e.Arguments()));
...
}
若要设置 XAML 按钮的内容属性,请调用 Button::Content mutator 函数。 若要将内容属性设置为字符串值,可以使用此代码。
Button().Content(winrt::box_value(L"Clicked"));
首先, hstring 转换构造函数将字符串文本转换为 hstring。 然后调用带有 hstring 参数的 winrt::box_value 重载。
取消装箱 IInspectable 的示例
在需要 IInspectable的函数中,可以使用 winrt::unbox_value 来取消装箱,并且可以使用 winrt::unbox_value_or 来使用默认值进行取消装箱。 还可以使用 try_as 解包到 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.
}
确定装箱值的类型
如果收到装箱值且不确定它包含的类型(需要知道其类型才能取消装箱),则可以查询其 IPropertyValue 接口的装箱值,然后对其调用 类型。 下面是一个代码示例。
WINRT_ASSERT
是宏定义,它扩展到 _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);