Note
你不僅可以對純量值進行框框和解框,還能透過 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 函式。 要將 content 屬性設為字串值,可以使用這段程式碼。
Button().Content(winrt::box_value(L"Clicked"));
首先, hstring 轉換建構器將字串的文字轉換成 hstring。 接著會觸發 winrt::box_value 的過載,需要一個 hstring 。
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 介面,然後對該介面呼叫 Type。 這裡有一個程式碼範例。
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);