通过 C++/WinRT 将标量值装箱到 IInspectable 和从 IInspectable 取消标量值装箱Boxing and unboxing scalar values to IInspectable with C++/WinRT

IInspectable 接口是 Windows 运行时 (WinRT) 中每个运行时类的根接口 。The IInspectable interface is the root interface of every runtime class in the Windows Runtime (WinRT). 这类似于位于每个 COM 接口和类的根处的 IUnknown;而且类似于位于每个通用类型系统类的根处的 System.Object 。This is an analogous idea to IUnknown being at the root of every COM interface and class; and System.Object being at the root of every Common Type System class.

换言之,可向任何运行时类的实例传递需要 IInspectable 的函数 。In other words, a function that expects IInspectable can be passed an instance of any runtime class. 但是你无法将标量值(如数值或文本值)直接传递到此类函数。But you can't directly pass a scalar value, such as a numeric or text value, to such a function. 相反,标量值需要封装到引用类对象内。Instead, a scalar value needs to be wrapped inside a reference class object. 该封装过程称为对值进行装箱That wrapping process is known as boxing the value.

重要

不管将什么类型传递给 Windows 运行时 API,都可以对该类型进行装箱和取消装箱操作。You can box and unbox any type that you can pass to a Windows Runtime API. 换言之,可以对 Windows 运行时类型这样做。In other words, a Windows Runtime type. 数字和文本值(字符串)是上面给出的示例。Numeric and text values (strings) are the examples given above. 另一个示例是在 IDL 中定义的 structAnother example is a struct that you define in IDL. 如果尝试对常规 C++ struct(未在 IDL 中定义)执行装箱操作,编译器会提醒你只能将 Windows 运行时类型装箱。If you try to box a regular C++ struct (one that's not defined in IDL), then the compiler will remind you that you can box only a Windows Runtime type. 运行时类是 Windows 运行时类型,不过,我们当然可以将运行时类传递到 Windows 运行时 API,无需将其装箱。A runtime class is a Windows Runtime type, but you can of course pass runtime classes to Windows Runtime APIs without boxing them.

C++/WinRT 提供了 winrt::box_value 函数,该函数采用标量值并将装箱的值返回到 IInspectable 中 。C++/WinRT provides the winrt::box_value function, which takes a scalar value and returns the value boxed into an IInspectable. 对于取消 IInspectable 装箱返回到标量值,提供 winrt::unbox_valuewinrt::unbox_value_or 函数 。For unboxing an IInspectable back into a scalar value, there are the winrt::unbox_value and winrt::unbox_value_or functions.

取消值装箱的示例Examples of boxing a value

LaunchActivatedEventArgs::Arguments 访问器函数返回 winrt::hstring,这是一个标量值 。The LaunchActivatedEventArgs::Arguments accessor function returns a winrt::hstring, which is a scalar value. 我们可以将该 hstring 值进行装箱并将其传递到需要 IInspectable 的函数,如下所示 。We can box that hstring value and pass it to a function that expects IInspectable like this.

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

要设置 XAML 按钮的内容属性,请调用 Button::Content 转变器函数 。To set the content property of a XAML Button, you call the Button::Content mutator function. 要将内容属性设置为字符串值,可以使用此代码。To set the content property to a string value, you can use this code.

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

首先,hstring 转换构造函数将此字符串参数转换为 hstring 。First, the hstring conversion constructor converts the string literal into an hstring. 然后,调用采用 hstring 的 winrt::box_value 的重载 。Then the overload of winrt::box_value that takes an hstring is invoked.

取消 IInspectable 装箱的示例Examples of unboxing an IInspectable

在自己的需要 IInspectable 的函数中,可以使用 winrt::unbox_value 取消装箱,也可以使用 winrt::unbox_value_or 通过默认值取消装箱 。In your own functions that expect IInspectable, you can use winrt::unbox_value to unbox, and you can use winrt::unbox_value_or to unbox with a default value.

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

确定装箱值的类型Determine the type of a boxed value

如果收到装箱值但不确定它所包含的类型(需要知道类型以便取消装箱),可以查询装箱值的 IPropertyValue 接口,然后对其调用 Type 。If you receive a boxed value and you're unsure what type it contains (you need to know its type in order to unbox it), then you can query the boxed value for its IPropertyValue interface, and then call Type on that. 下面是代码示例。Here's a code example.

WINRT_ASSERT 是宏定义,并且扩展到 _ASSERTEWINRT_ASSERT is a macro definition, and it expands to _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);

重要的 APIImportant APIs