Kolekcje (C++/CX)
W programie C++/CX można bezpłatnie korzystać z kontenerów standardowej biblioteki szablonów (STL) lub dowolnego innego typu kolekcji zdefiniowanego przez użytkownika. Jednak w przypadku przekazywania kolekcji w środowisko wykonawcze systemu Windows interfejs binarny aplikacji (ABI) — na przykład do kontrolki XAML lub klienta JavaScript — należy użyć środowisko wykonawcze systemu Windows typów kolekcji.
Środowisko wykonawcze systemu Windows definiuje interfejsy kolekcji i powiązanych typów, a C++/CX udostępnia konkretne implementacje języka C++ w pliku nagłówkowym collection.h. Na tej ilustracji przedstawiono relacje między typami kolekcji:
Klasa Platform::Collections::Vector przypomina klasę std::vector.
Klasa Platform::Collections::Map przypomina klasęstd::map.
Map
Iteratory są definiowane w przestrzeni nazw Platform::Collections. Te iteratory spełniają wymagania iteratorów STL i umożliwiają korzystanie z interfejsu std::find, std::count_if i innych algorytmów STL w dowolnym typie interfejsu Windows::Foundation::Collections lub Typ betonu Platform::Collections. Oznacza to na przykład, że można iterować kolekcję w składniku środowisko wykonawcze systemu Windows utworzonym w języku C# i zastosować do niego algorytm STL.
Ważne
Iteratory serwerów
VectorIterator
proxy iVectorViewIterator
korzystają z obiektów proxy orazVectoryProxy<T>
do włączania użycia z konteneramiArrowProxy<T>
STL. Aby uzyskać więcej informacji, zobacz "VectorProxy elements" w dalszej części tego artykułu.Typy kolekcji C++/CX obsługują te same zabezpieczenia wątków, które obsługują kontenery STL.
Windows::Foundation::Collections::IObservableVector i Windows::Foundation::Collections::IObservableMap definiują zdarzenia, które są wyzwalane, gdy kolekcja zmienia się na różne sposoby. Implementując te interfejsy, platform::Collections::Map i Platform::Collections::Vector obsługują powiązanie danych z kolekcjami XAML. Jeśli na przykład element
Vector
jest powiązany z elementemGrid
, po dodaniu elementu do kolekcji zmiana zostanie odzwierciedlona w interfejsie użytkownika siatki.
Użycie wektorów
Jeśli klasa musi przekazać kontener sekwencji do innego składnika środowisko wykonawcze systemu Windows, użyj polecenia Windows::Foundation::Collections:: IVector<T> jako parametru lub zwracanego typu oraz platform::Collections::Vector<T> jako konkretnej implementacji. Jeśli spróbujesz użyć Vector
typu w publicznej wartości zwracanej lub parametrze, zostanie zgłoszony błąd kompilatora C3986. Możesz rozwiązać ten problem, zmieniając Vector
element na IVector
.
Ważne
Jeśli przekazujesz sekwencję w ramach własnego programu, użyj metody Vector
lub std::vector
, ponieważ są one bardziej wydajne niż IVector
. Używaj IVector
tylko wtedy, gdy przekazujesz kontener w usłudze ABI.
System typów środowisko wykonawcze systemu Windows nie obsługuje koncepcji tablic postrzępionych i dlatego nie można przekazać IVector<Platform::Array<T>>
jako wartości zwracanej lub parametru metody. Aby przekazać tablicę postrzępionych lub sekwencję sekwencji w usłudze ABI, użyj polecenia IVector<IVector<T>^>
.
Vector<T>
Udostępnia metody wymagane do dodawania, usuwania i uzyskiwania dostępu do elementów w kolekcji oraz niejawnie konwertowane na IVector<T>
. Można również używać algorytmów STL w wystąpieniach programu Vector<T>
. W poniższym przykładzie pokazano pewne podstawowe użycie. Funkcja begin i end znajdują się tutaj w Platform::Collections
przestrzeni nazw, a nie z std
przestrzeni nazw.
#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();
}
Jeśli masz istniejący kod, który używa std::vector
metody i chcesz użyć go ponownie w składniku środowisko wykonawcze systemu Windows, wystarczy użyć jednego z Vector
konstruktorów, który przyjmuje std::vector
iteratory lub parę iteratorów do konstruowania Vector
w punkcie, w którym przekazujesz kolekcję w usłudze ABI. W poniższym przykładzie pokazano, jak używać konstruktora przenoszenia do wydajnego Vector
inicjowania z klasy std::vector
. Po operacji przenoszenia oryginalna vec
zmienna nie jest już prawidłowa.
//#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));
}
Jeśli w pewnym momencie masz wektor ciągów, które należy przekazać przez usługę ABI w przyszłości, musisz zdecydować, czy początkowo utworzyć ciągi jako std::wstring
typy, czy jako Platform::String^
typy. Jeśli musisz wykonać wiele czynności przetwarzania w ciągach, użyj polecenia wstring
. W przeciwnym razie utwórz ciągi jako Platform::String^
typy i unikaj ich późniejszego konwertowania. Należy również zdecydować, czy umieścić te ciągi w std:vector
obiekcie , czy Platform::Collections::Vector
wewnętrznie. Ogólnie rzecz biorąc, należy użyć elementu std::vector
, a następnie utworzyć go Platform::Vector
tylko wtedy, gdy przekazujesz kontener w usłudze ABI.
Typy wartości w wektorze
Każdy element, który ma być przechowywany w elemecie Platform::Collections::Vector , musi obsługiwać porównywanie równości, niejawnie lub przy użyciu niestandardowego modułu std::equal_to , który podajesz. Wszystkie typy odwołań i wszystkie typy skalarne niejawnie obsługują porównania równości. W przypadku typów wartości innych niż skalarne, takich jak Windows::Foundation::D ateTime lub dla porównań niestandardowych — na przykład objA->UniqueID == objB->UniqueID
— należy podać obiekt funkcji niestandardowej.
Elementy VectorProxy
Platform::Collections::VectorIterator i Platform::Collections::VectorViewIterator umożliwiają korzystanie range for
z pętli i algorytmów, takich jak std::sort z kontenerem IVector<T>. Nie można jednak IVector
uzyskać dostępu do elementów za pośrednictwem wyłudżenia wskaźnika języka C++. Dostęp do nich można uzyskać tylko za pośrednictwem metod GetAt i SetAt . W związku z tym te iteratory używają klas Platform::Details::VectorProxy<T>
proxy i Platform::Details::ArrowProxy<T>
zapewniają dostęp do poszczególnych elementów za pośrednictwem *operatorów , ->, i [], zgodnie z wymaganiami biblioteki standardowej. Ściśle rzecz biorąc, biorąc pod uwagę IVector<Person^> vec
, typ *begin(vec)
to VectorProxy<Person^>
. Jednak obiekt proxy jest prawie zawsze niewidoczny dla kodu. Te obiekty serwera proxy nie są udokumentowane, ponieważ są przeznaczone tylko do użytku wewnętrznego przez iteratory, ale warto wiedzieć, jak działa mechanizm.
Jeśli używasz pętli opartej na for
zakresie dla IVector
kontenerów, użyj polecenia auto&&
, aby umożliwić zmiennej iteratora prawidłowe powiązanie z elementami VectorProxy
. Jeśli używasz auto&
polecenia , zostanie zgłoszone ostrzeżenie kompilatora C4239 i VectoryProxy
zostanie wymienione w tekście ostrzegawczym.
Poniższa ilustracja przedstawia pętlę range for
na obiekcie IVector<Person^>
. Zwróć uwagę, że wykonanie zostało zatrzymane w punkcie przerwania w wierszu 64. Okno QuickWatch pokazuje, że zmienna iteratora jest w rzeczywistości zmienną p
zawierającą VectorProxy<Person^>
m_v
zmienne składowe i m_i
. Jednak wywołanie GetType
tej zmiennej powoduje zwrócenie identycznego Person
typu do wystąpienia p2
. Na wynos jest to, że chociaż VectorProxy
i ArrowProxy
może występować w QuickWatch, debugerze niektórych błędów kompilatora lub innych miejscach, zwykle nie trzeba jawnie kodować dla nich.
Jednym ze scenariuszy, w którym trzeba kodować wokół obiektu proxy, jest dynamic_cast
wykonanie elementu na elementach — na przykład w przypadku wyszukiwania obiektów XAML określonego typu w UIElement
kolekcji elementów. W takim przypadku należy najpierw rzutować element na platform::Object^, a następnie wykonać rzutowanie dynamiczne:
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...
}
}
}
Mapuj użycie
W tym przykładzie pokazano, jak wstawić elementy i wyszukać je w typie Platform::Collections::Map, a następnie zwrócić element Map
jako tylko do odczytu 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();
}
Ogólnie rzecz biorąc, w przypadku funkcji wewnętrznej mapy preferuj std::map
typ ze względów wydajności. Jeśli musisz przekazać kontener w usłudze ABI, skonstruuj obiekt Platform::Collections::Map z pliku std::map i zwróć go Map
jako element Windows::Foundation::Collections::IMap. Jeśli spróbujesz użyć Map
typu w publicznej wartości zwracanej lub parametrze, zostanie zgłoszony błąd kompilatora C3986. Możesz rozwiązać ten problem, zmieniając Map
element na IMap
. W niektórych przypadkach — na przykład jeśli nie wykonujesz dużej liczby odnośników lub wstawiania, a często przekazujesz kolekcję w usłudze ABI — może to być tańsze w użyciu Platform::Collections::Map
od początku i uniknięcie kosztów konwersji std::map
elementu . W każdym razie należy unikać operacji wyszukiwania i wstawiania na obiekcie IMap
, ponieważ są one najmniej wydajne dla trzech typów. Przekonwertuj wartość na IMap
tylko w momencie przekazania kontenera w usłudze ABI.
Typy wartości w mapie
Elementy w elemecie Platform::Collections::Map są uporządkowane. Każdy element, który ma być przechowywany w obiekcie Map
, musi obsługiwać mniej niż porównanie ze ścisłym słabym porządkoweniem, niejawnie lub przy użyciu niestandardowego modułu stl::less , który podajesz. Typy skalarne obsługują porównanie niejawnie. W przypadku typów wartości innych niż skalarne, takich jak Windows::Foundation::DateTime
, lub dla porównań niestandardowych — na przykład objA->UniqueID < objB->UniqueID
— należy podać niestandardowy komparator.
Typy kolekcji
Kolekcje dzielą się na cztery kategorie: modyfikowalne wersje i wersje tylko do odczytu kolekcji sekwencji i kolekcje asocjacyjne. Ponadto język C++/CX rozszerza kolekcje, zapewniając trzy klasy iteracyjne, które upraszczają dostęp do kolekcji.
Elementy kolekcji modyfikowalnej można zmienić, ale elementy kolekcji tylko do odczytu, znanej jako widok, mogą być odczytywane tylko. Dostęp do elementów kolekcji Platform::Collections::Vector lubPlatform::Collections::VectorView można uzyskać za pomocą iteratora lub kolekcji Vector::GetAt i indeksu. Dostęp do elementów kolekcji asocjacyjnej można uzyskać przy użyciu kolekcji Map::Lookup i klucza.
Platform::Collections::Map, klasa
Kolekcja asocjacyjna, modyfikowalna. Elementy mapy to pary klucz-wartość. Wyszukanie klucza w celu pobrania skojarzonej wartości i iterowanie wszystkich par klucz-wartość jest obsługiwane.
Map
i MapView
są szablony w systemie <K, V, C = std::less<K>>
; w związku z tym można dostosować komparator. Ponadto element i Vector
są szablonamiVectorView
, <T, E = std::equal_to<T>>
dzięki czemu można dostosować zachowanie elementu IndexOf()
. Jest to ważne głównie dla Vector
VectorView
i struktur wartości. Aby na przykład utworzyć wektor<Windows::Foundation::D ateTime>, należy podać niestandardowy komparator, ponieważ funkcja DateTime nie przeciąża operatora ==.
Platform::Collections::MapView, klasa
Wersja tylko do odczytu obiektu Map
.
Platform::Collections::Vector, klasa
Kolekcja sekwencji modyfikowalna.
Vector<T>
obsługuje dostęp losowy w czasie stałym oraz operacje dołączania w amortyzowanym stałym czasie.
Platform::Collections::VectorView, klasa
Wersja tylko do odczytu obiektu Vector
.
Platform::Collections::InputIterator, klasa
Iterator STL spełniający wymagania iteratora wejściowego STL.
Platform::Collections::VectorIterator, klasa
Iterator STL spełniający wymagania iteratora ZTL modyfikowalnego losowego dostępu.
Platform::Collections::VectorViewIterator, klasa
Iterator STL spełniający wymagania iteratora dostępu losowego STL const
.
funkcje begin() i end()
Aby uprościć korzystanie z biblioteki STL do przetwarzania Vector
obiektów , , VectorView
, Map
MapView
i dowolnychWindows::Foundation::Collections
, język C++/CX obsługuje przeciążenia funkcji begin i funkcji końcowej, które nie są elementami składowymi.
W poniższej tabeli wymieniono dostępne iteratory i funkcje.
Iteratory | Funkcje |
---|---|
Platform::Collections::VectorIterator<T> (Magazyny wewnętrzneWindows::Foundation::Collections:: IVector<T> i int). |
begin/ end(Windows::Foundation::Collections:: IVector<T>) |
Platform::Collections::VectorViewIterator<T> (Magazyny wewnętrzneIVectorView<T>^ i int). |
begin/ end (IVectorView<T>^) |
Platform::Collections::InputIterator<T> (Magazyny wewnętrzneIIterator<T>^ i T.) |
begin/ end (IIterable<T>) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Magazyny wewnętrzneIIterator<T>^ i T.) |
begin/ end (IMap<K,V>. |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^> (Magazyny wewnętrzneIIterator<T>^ i T.) |
begin/ end (Windows::Foundation::Collections::IMapView) |
Zdarzenia zmiany kolekcji
Vector
obsługa Map
powiązania danych w kolekcjach XAML przez zaimplementowanie zdarzeń występujących po zmianie lub zresetowaniu obiektu kolekcji albo wstawienie, usunięcie lub zmianę dowolnego elementu kolekcji. Możesz napisać własne typy, które obsługują powiązanie danych, chociaż nie można dziedziczyć z Map
lub Vector
dlatego, że te typy są zapieczętowane.
Delegaty windows::Foundation::Collections::VectorChangedEventHandler i Windows::Foundation::Collections::MapChangedEventHandler określają podpisy procedur obsługi zdarzeń dla zdarzeń dotyczących zdarzeń zmiany. Klasy wyliczenia publicznego Windows::Foundation::Collections::CollectionChange oraz Platform::Collection::Details::MapChangedEventArgs
Platform::Collections::Details::VectorChangedEventArgs
klasy ref przechowują argumenty zdarzeń, aby określić przyczynę zdarzenia. Typy *EventArgs
są definiowane w Details
przestrzeni nazw, ponieważ nie trzeba ich konstruować ani używać jawnie podczas korzystania z programu Map
lub Vector
.
Zobacz też
System typów
Dokumentacja języka C++/CX
Dokumentacja przestrzeni nazw