集合 (C++/CX)

在 C++/CX 程式中,您可以自由使用標準範本連結庫 (STL) 容器或任何其他使用者定義集合類型。 不過,當您在 Windows 執行階段 應用程式二進位介面 (ABI) 之間來回傳遞集合時,例如,將集合傳遞至 XAML 控制項或 JavaScript 用戶端時,您必須使用 Windows 執行階段 集合類型。

Windows 執行階段 會定義集合和相關類型的介面,而 C++/CX 會在 collection.h 頭檔中提供具體的 C++ 實作。 下圖顯示集合型別之間的關聯性:

Diagram of C plus plus C X inheritance tree for collection types.

向量用法

當您的類別必須將序列容器傳遞至另一個 Windows 執行階段 元件時,請使用 Windows::Foundation::Collections:: IVector<T 做為參數或傳回型別,而 Platform::Collections::Vector<T>> 做為具體實作。 如果您嘗試在公用傳回值或參數中使用 Vector 類型,則會引發編譯器錯誤 C3986。 只要將 Vector 變更為 IVector,就可以修正這個錯誤。

重要

如果您在自己的程式中傳遞序列,則使用 Vectorstd::vector ,因為這些方法比 IVector更有效率。 只有在透過 ABI 傳遞容器時,才應該使用 IVector

Windows 執行階段 類型系統不支援不規則數位的概念,因此您無法傳遞 IVector<Platform::Array<T>> 做為傳回值或方法參數。 若要跨 ABI 傳遞不規則陣列或一組序列中的某個序列,請使用 IVector<IVector<T>^>

Vector<T> 提供在集合中新增、移除和存取項目的必要方法,此集合可隱含轉換為 IVector<T>。 您也可以在 Vector<T>的執行個體上使用 STL 演算法。 下列範例示範一些基本用法。 這裡的 begin 函式end 函式 來自 Platform::Collections 命名空間,而非 std 命名空間。

#include <collection.h>
#include <algorithm>
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation::Collections;


void Class1::Test()
{
    Vector<int>^ vec = ref new Vector<int>();
    vec->Append(1);
    vec->Append(2);
    vec->Append(3);
    vec->Append(4);
    vec->Append(5);


    auto it = 
        std::find(begin(vec), end(vec), 3);

    int j = *it; //j = 3
    int k = *(it + 1); //or it[1]

    // Find a specified value.
    unsigned int n;         
    bool found = vec->IndexOf(4, &n); //n = 3

    // Get the value at the specified index.
    n = vec->GetAt(4); // n = 3

    // Insert an item.
    // vec = 0, 1, 2, 3, 4, 5
    vec->InsertAt(0, 0);

    // Modify an item.
    // vec = 0, 1, 2, 12, 4, 5,
    vec->SetAt(3, 12);

    // Remove an item.
    //vec = 1, 2, 12, 4, 5 
    vec->RemoveAt(0);

    // vec = 1, 2, 12, 4
    vec->RemoveAtEnd();

    // Get a read-only view into the vector.
    IVectorView<int>^ view = vec->GetView();
}

如果您有使用 std::vector 的現有程式碼,而且想要在 Windows 執行階段元件中重複使用它,只要使用其中一Vector個採用 std::vector 或 一組反覆運算器的建構函式,即可在您將集合傳遞至 ABI 的點建構 Vector 。 下列範例示範如何從 Vector 使用 std::vector移動建構函式,以提高初始化效率。 在移動作業後,原始 vec 變數就不再有效。

//#include <collection.h>
//#include <vector>
//#include <utility> //for std::move
//using namespace Platform::Collections;
//using namespace Windows::Foundation::Collections;
//using namespace std;
IVector<int>^ Class1::GetInts()
{
    vector<int> vec;
    for(int i = 0; i < 10; i++)
    {
        vec.push_back(i);
    }    
    // Implicit conversion to IVector
    return ref new Vector<int>(std::move(vec));
}

如果您必須在未來透過 ABI 傳遞字串向量,您必須決定最初以 std::wstring 型別或 Platform::String^ 型別建立字串。 如果您必須對字串進行許多處理,則使用 wstring。 否則,請以 Platform::String^ 類型建立字串,以避免稍後進行轉換的成本。 您也必須決定是否要將這些字串放入 std:vectorPlatform::Collections::Vector 內部。 一般的作法是,只有在您透過 ABI 傳遞容器時,才使用 std::vector ,然後從中建立 Platform::Vector

Vector 中的實值類型

要儲存在 Platform::Collections::Vector 中的所有元素都必須隱含或透過您提供的自訂 std::equal_to 比較子支援相等比較。 所有參考型別及所有純量型別都隱含支援相等比較。 針對非純量實值類型 (例如 Windows::Foundation::DateTime) 或自訂比較 (例如 objA->UniqueID == objB->UniqueID),您必須提供自訂函式物件。

VectorProxy 元素

Platform::Collections::VectorIterator 和 Platform::Collections::VectorViewIterator 可讓您搭配 IVector<T> 容器使用 range for std::sort迴圈和演算法。 但是,您無法透過 C++ 指標取值存取 IVector 項目,只能透過 GetAtSetAt 方法存取。 因此,這些反覆運算器會使用 Proxy 類別Platform::Details::VectorProxy<T>,並Platform::Details::ArrowProxy<T>視標準連結庫的需求,透過*>[] 運算子提供個別元素的存取權。 嚴格來說,如果指定 IVector<Person^> vec,則 *begin(vec) 的類型就是 VectorProxy<Person^>。 不過,對您的程式碼來說,Proxy 物件永遠都像是不存在一樣。 這些 Proxy 物件沒有記錄在文件中,因為它們僅供迭代器在內部使用,但是了解機制如何運作還是很重要。

當您在容器上使用範圍型for循環時,請使用 auto&& 來讓反覆運算器變數正確地系結至VectorProxyIVector元素。 如果您使用 auto&,則會引發編譯程式警告 C4239 ,並在 VectoryProxy 警告文字中提及。

下圖顯示針對 range for 執行的 IVector<Person^>迴圈。 請注意,程式會執行到第 64 行的中斷點停止。 [ 快速監看式 ] 視窗會顯示迭代器變數 p 就是擁有 VectorProxy<Person^>m_v 成員變數的 m_i 。 但是,當您針對這個變數呼叫 GetType 時,它會將相同的類型傳回給 Person 執行個體 p2。 因此,雖然 VectorProxyArrowProxy 可能會出現在 [ 快速監看式]、偵錯工具、某些編譯器錯誤或其他位置,但是一般而言,您仍然不必明確為它們撰寫程式碼。

Screenshot of debugging VectorProxy in a range based for loop.

有一種情況下您必須為 Proxy 物件撰寫程式碼,就是必須針對元素執行 dynamic_cast 的時候 (例如,當您在 UIElement 項目集合中尋找特定類型的 XAML 物件時)。 在這種情況下,您必須先將這個項目轉換為 Platform::Object^,然後再執行動態轉換:

void FindButton(UIElementCollection^ col)
{
    // Use auto&& to avoid warning C4239
    for (auto&& elem : col)
    {
        Button^ temp = dynamic_cast<Button^>(static_cast<Object^>(elem));
        if (nullptr != temp)
        {
            // Use temp...
        }
    }
}

對應用法

這個範例示範如何插入項目及在 Platform::Collections::Map中查閱項目,然後傳回 Map 作為唯讀 Windows::Foundation::Collections::IMapView 類型。

//#include <collection.h>
//using namespace Platform::Collections;
//using namespace Windows::Foundation::Collections;
IMapView<String^, int>^ Class1::MapTest()
{
    Map<String^, int>^ m = ref new Map<String^, int >();
    m->Insert("Mike", 0);
    m->Insert("Dave", 1);
    m->Insert("Doug", 2);
    m->Insert("Nikki", 3);
    m->Insert("Kayley", 4);
    m->Insert("Alex", 5);
    m->Insert("Spencer", 6);

   // PC::Map does not support [] operator
   int i = m->Lookup("Doug");
   
   return m->GetView();
   
}

一般而言,基於效能考量,在內部對應功能上最好使用 std::map 型別。 如果您必須透過 ABI 傳遞容器,請從 std::map 建構 Platform::Collections::Map ,然後傳回 Map 作為 Windows::Foundation::Collections::IMap。 如果您嘗試在公用傳回值或參數中使用 Map 類型,則會引發編譯器錯誤 C3986。 只要將 Map 變更為 IMap,就可以修正這個錯誤。 在某些情況下,例如,如果不是進行大量搜尋或插入,且您經常透過 ABI 傳遞集合,則一開始便使用 Platform::Collections::Map 可耗費較少資源,還能避免轉換 std::map時的成本。 在任何情況下,請避免在 IMap 上執行查閱和插入作業,因為這些是效能最低的三個類型。 只有在透過 ABI 傳遞容器時,才應該轉換為 IMap

Map 中的實值類型

Platform::Collections::Map 中的項目已排序。 要儲存在 Map 中的所有項目都必須隱含或透過您提供的自訂 stl::less 比較子,支援使用嚴格弱式順序的小於比較。 純量類型隱含支援此比較。 針對非純量實值類型 (例如 Windows::Foundation::DateTime) 或自訂比較 (例如 objA->UniqueID < objB->UniqueID),您必須提供自訂比較子。

集合類型

集合分成四種分類:序列集合和關聯集合的可修改版本和唯讀版本。 此外,C++/CX 提供三個反覆運算器類別來簡化集合的存取,藉此增強集合。

您可以變更可修改的集合的元素,但只能讀取唯讀集合的元素,又稱為 檢視 (View)。 Platform::Collections::Vector 或 Platform::Collections::VectorView 集合的專案可以使用反覆運算器或集合的 Vector::GetAt 和索引來存取。 您可以使用集合的 Map::Lookup 和索引鍵來存取關聯集合的專案。

Platform::Collections::Map 類別
可修改的關聯集合。 對應元素是機碼值組。 支援查閱機碼以擷取其關聯值與逐一查看所有機碼值組。

MapMapView<K, V, C = std::less<K>>為樣板,因此,您可以自訂比較子。 此外, VectorVectorView<T, E = std::equal_to<T>> 為樣板,因此,您可以自訂 IndexOf()的行為。 這對於值結構的 VectorVectorView 而言十分重要。 例如,若要建立向量<Windows::Foundation::D ateTime>,您必須提供自定義比較子,因為DateTime不會多載 == 運算符。

Platform::Collections::MapView 類別
Map的唯讀版本。

Platform::Collections::Vector 類別
可修改的序列集合。 Vector<T> 支援固定時間隨機存取和分期固定時間 Append 作業。

Platform::Collections::VectorView 類別
Vector的唯讀版本。

Platform::Collections::InputIterator 類別
滿足 STL 輸入迭代器需求的 STL 迭代器。

Platform::Collections::VectorIterator 類別
滿足 STL 可變動隨機存取迭代器需求的 STL 迭代器。

Platform::Collections::VectorViewIterator 類別
符合 STL 隨機存取反覆運算器需求的 STL const 反覆運算器。

begin() 和 end() 函式

為了簡化 STL 來處理 、、、 和 任意Windows::Foundation::Collections物件的使用,C++/CX 支援 begin Function 和 end Function 非成員函式的多載。 MapViewMapVectorViewVector

下表列出可用的迭代器和函式。

迭代器 函式
Platform::Collections::VectorIterator<T>

(內部存放區 Windows::Foundation::Collections:: IVector<T> 和 int.
begin/ endWindows::Foundation::Collections:: IVector<T>
Platform::Collections::VectorViewIterator<T>

(內部存放區 IVectorView<T>^ 和 int.
begin/ endIVectorView<T>^)
Platform::Collections::InputIterator<T>

(內部存放區 IIterator<T>^ 和 T.)
begin/ endIIterable<T>
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(內部存放區 IIterator<T>^ 和 T.)
begin/ endIMap<K,V>.
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>

(內部存放區 IIterator<T>^ 和 T.)
begin/ end (Windows::Foundation::Collections::IMapView)

集合變更事件

VectorMap 藉由實作變更或重設集合物件時,或者插入、移除或變更集合的任何元素時所發生的事件,來支援 XAML 集合中的資料繫結。 您可以撰寫自己的型別來支援資料繫結,但是您無法繼承自 MapVector ,因為這些型別是密封型別。

Windows::Foundation::Collections::VectorChangedEventHandlerWindows::Foundation::Collections::MapChangedEventHandler 委派會為集合變更事件的事件處理常式指定簽章。 Windows::Foundation::Collections::CollectionChange 公用列舉類別及 Platform::Collection::Details::MapChangedEventArgsPlatform::Collections::Details::VectorChangedEventArgs ref 類別會儲存事件引數,以判斷造成事件的原因。 類型*EventArgs是在 命名空間中Details定義,因為當您使用 或 Vector時,不需要明確地建構或取Map用它們。

另請參閱

類型系統
C++/CX 語言參考
命名空間參考