Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
18.1 Ogólne
Ta klauzula wprowadza model dla rozszerzonych typów kolekcjiz możliwością indeksowania i fragmentowania opartych na:
- Typy wprowadzone w niniejszej klauzuli (
System.Index§18.2) iSystem.Range(§18.3); - Wstępnie zdefiniowane operatory jednoargumentowe
^(§12.9.6) i binarne..(§12.10) oraz - Wyrażenie element_access .
W modelu typ jest klasyfikowany jako:
- kolekcja, jeśli reprezentuje grupę elementóws
-
rozszerzona kolekcja indeksowalna, jeśli obsługuje wyrażenie element_access, które ma jedno wyrażenie argumentu typu
Index, które zwraca i/lub ustawia pojedynczy element typu, według wartości lub odwołania; i -
rozszerzona kolekcja fragmentowalna, jeśli obsługuje wyrażenie element_access, które ma jedno wyrażenie argumentu typu
Range, które zwraca fragment elementów typu według wartości.
Uwaga: model nie wymaga ustawienia wycinka typu, ale typ może obsługiwać go jako rozszerzenie modelu. notatka końcowa
Model jest obsługiwany w przypadku tablic jednowymiarowych (§12.8.12.2) i ciągów (§12.8.12.3).
Model może być obsługiwany przez dowolną klasę, strukturę lub typ interfejsu, który zapewnia odpowiednie indeksatory (§15.9), które implementują semantyka modelu.
Niejawna obsługa modelu jest udostępniana dla typów, które nie obsługują go bezpośrednio, ale które zapewniają określony wzorzec elementów członkowskich (§18.4). Ta obsługa jest oparta na wzorcu, a nie na podstawie semantyki, ponieważ semantyka elementów członkowskich typu, na których jest oparta, są zakładane — język nie wymusza ani nie sprawdza semantyki tych elementów członkowskich typu.
Dla celów tej klauzuli definiowane są następujące terminy:
- Kolekcja jest typem reprezentującym grupę elementóws.
- Kolekcja zliczalna to kolekcja, która udostępnia właściwość zliczalną właściwość
int-valued wystąpienia, której wartość jest liczbą elementów aktualnie w grupie. Ta właściwość ma nazwęLengthlubCount. Pierwszy jest wybierany, jeśli oba istnieją. -
Sekwencja lub typ indeksowalny to kolekcja:
- które jest liczone;
- gdzie dostęp do każdego elementu można uzyskać przy użyciu wyrażenia element_access z jednym wymaganym
intargumentem, indeks od początku, dodatkowe opcjonalne argumenty są dozwolone; - sekwencja jest modyfikowalna , jeśli każdy element można również ustawić przy użyciu wyrażenia element_access ;
- indeks od początku elementu to liczba elementów przed nim w sekwencji dla sekwencji zawierającej N elementów:
- pierwsze i ostatnie elementy mają odpowiednio indeksy 0 i N-1 oraz
- indeks przeszłości, indeks, który reprezentuje hipotetyczny element po ostatnim, ma wartość N.
- Indeks od końca reprezentuje pozycję elementu w sekwencji względem indeksu przeszłości. W przypadku sekwencji zawierającej N elementów pierwsze, ostatnie i ostatnie indeksy są odpowiednio N, 1 i 0.
- Zakres to ciągły przebieg zera lub większej liczby indeksów rozpoczynających się od dowolnego indeksu w ramach sekwencji.
- Wycinek to kolekcja elementów w zakresie.
-
Kolekcja z możliwością fragmentatora jest kolekcją, która:
- jest liczone;
- Udostępnia metodę
Slice, która przyjmuje dwaintparametry określające zakres, będąc indeksem początkowym i liczbą elementów, i zwraca nowy fragment skonstruowany z elementów w zakresie.
Powyższe definicje są rozszerzone na potrzeby zastosowań Index i Range w następujący sposób:
- Typ jest również sekwencją , jeśli wyrażenie element_access przyjmuje jeden wymagany
Indexargument, a nieintargument, jest obsługiwany. W przypadku, gdy wymagane jest rozróżnienie, typ jest określany jako rozszerzony indeksowalny. - Typ jest również fragmentowalny , jeśli wyrażenie element_access przyjmuje jeden wymagany
Rangeargument, a nie metodęSlice, jest obsługiwany. W przypadku gdy wymagane jest rozróżnienie, typ jest określany jako rozszerzony fragmentator.
Określa, czy typ jest klasyfikowany jako zliczany, indeksowalny lub fragmentowalny, podlega ograniczeniom ułatwień dostępu składowych (§7.5) i w związku z tym zależy od tego, gdzie jest używany typ.
Przykład: typ, w którym właściwość zliczalna i/lub indeksator są
protectedtylko sekwencją elementów członkowskich i wszystkich typów pochodnych. przykład końcowy
Wymagane elementy członkowskie typu do zakwalifikowania się jako sekwencja lub fragmentowalne mogą być dziedziczone.
Przykład: w poniższym kodzie
public class A { public int Length { get { … } } } public class B : A { public int this(int index) { … } } public class C : B { public int[] Slice(int index, int count) { … } }Typ
Ajest zliczalny,Bjest sekwencją i jest fragmentowalny iCsekwencja.przykład końcowy
Note:
- Typ może być fragmentowalny bez indeksowania ze względu na brak indeksatora (dostępnego).
- Typ, który ma być fragmentowalny i/lub indeksowalny, wymaga, aby typ był zliczalny.
- Chociaż elementy sekwencji są uporządkowane według pozycji w sekwencji, same elementy nie muszą być uporządkowane według ich wartości, a nawet uporządkowane.
notatka końcowa
18.2 Typ indeksu
Typ System.Index reprezentuje indeks abstrakcyjny , który reprezentuje indeks od początku lub indeks od końca.
public readonly struct Index : IEquatable<Index>
{
public int Value { get; }
public bool IsFromEnd { get; }
public Index(int value, bool fromEnd = false);
public static implicit operator Index(int value);
public int GetOffset(int length);
public bool Equals(Index other);
}
Index wartości są konstruowane na podstawie int, określając przesunięcie nieujemne i bool, wskazując, czy przesunięcie jest od końca (true) lub początku (false). Jeśli określone przesunięcie jest ujemne, ArgumentOutOfRangeException zostanie zgłoszony.
Przykład
Index first = new Index(0, false); // first element index var last = new Index(1, true); // last element index var past = new Index(0, true); // past-end index Index invalid = new Index(-1); // throws ArgumentOutOfRangeExceptionprzykład końcowy
Istnieje niejawna konwersja, z intIndex której tworzy indeksy od początku, oraz zdefiniowany język operator ^ jednoargumentowy (§12.9.6), z intIndex którego tworzy indeksy z końca.
Przykład
Korzystając z niejawnych konwersji i operatora jednoargumentowego
^, można napisać powyższe przykłady:Index first = 0; // first element index var last = ^1; // last element index var past = ^0; // past-end indexprzykład końcowy
Metoda GetOffset konwertuje wartość abstrakcyjną Index na konkretną int wartość indeksu dla sekwencji określonego lengthelementu .
Index Jeśli wartość I, , jest od końca ta metoda zwraca tę samą wartość co length - I.Value, w przeciwnym razie zwraca tę samą wartość co I.Value.
Ta metoda nie sprawdza, czy wartość zwracana znajduje się w prawidłowym 0 zakresie włącznie length-1 .
Nuta: Nie określono sprawdzania, ponieważ oczekiwane użycie wyniku polega na indeksowaniu do sekwencji z elementami
length, a operacja indeksowania ma wykonać odpowiednie kontrole. notatka końcowa
Index implementuje IEquatable<Index> i wartości można porównać pod kątem równości na podstawie wartości abstrakcyjnej; dwie Index wartości są równe, jeśli i tylko wtedy, gdy odpowiednie Value i IsFromEnd właściwości są równe. Jednak Index wartości nie są uporządkowane i nie są udostępniane żadne inne operacje porównania.
Nuta:
Indexwartości są nieuporządkowane, ponieważ są abstrakcyjne indeksy, ogólnie rzecz biorąc, nie można określić, czy indeks od końca występuje przed lub po indeksie od początku bez odwołania do długości sekwencji. Po przekonwertowaniu na konkretne indeksy, np. wedługGetOffset, te konkretne indeksy są porównywalne. notatka końcowa
Index wartości mogą być używane bezpośrednio w argument_list wyrażenia element_access (§12.8.12), czyli:
- dostęp do tablicy, a obiekt docelowy jest tablicą jednowymiarową (§12.8.12.2);
- dostęp do ciągu (§12.8.12.3)
- dostęp indeksatora i typ docelowy ma indeksator z odpowiednimi parametrami
Indextypu (§12.8.12.4) lub typu, do któregoIndexwartości są niejawnie konwertowane; lub - dostęp indeksatora i typ docelowy są zgodne ze wzorcem sekwencji, dla którego określono niejawną
Indexobsługę (§18.4.2).
18.3 Typ zakresu
Typ System.Range reprezentuje abstrakcyjny zakres Indexwartości od indeksu do indeksu Start , ale nie uwzględnia indeksu End .
public readonly struct Range : IEquatable<Index>
{
public Index Start { get; }
public Index End { get; }
public Range(Index start, Index end);
public (int Offset, int Length) GetOffsetAndLength(int length);
public bool Equals(Range other);
}
Range wartości są tworzone na podstawie dwóch Index wartości.
Przykład
W poniższych przykładach użyto niejawnej konwersji z
intdoIndex(§18.2) i^operatora (§12.9.6), aby utworzyćIndexwartości dla każdegoRangeelementu :var firstQuad = new Range(0, 4); // the indices from `0` to `3` // int values impicitly convert to `Index` var nextQuad = new Range(4, 8); // the indices from `4` to `7` var wholeSeq = new Range(0, ^0); // the indices from `0` to `N-1` where `N` is the // length of the sequence wholeSeq is used with var dropFirst = new Range(1, ^0); // the indices from `1` to `N-1` var dropLast = new Range(0, ^1); // the indices from `0` to `N-2` var maybeLast = new Range(^1, 6); // the indices from `N-1` to 5 var lastTwo = new Range(^2, ^0); // the indices from `N-2` to `N-1`przykład końcowy
Operator .. zdefiniowany przez język (§12.10) tworzy Range wartość na podstawie Index wartości.
Przykład
..Za pomocą operatora można napisać powyższe przykłady:var firstQuad = 0..4; // the indices from `0` to `3` var nextQuad = 4..8; // the indices from `4` to `7` var wholeSeq = 0..^0; // the indices from `0` to `N-1` var dropFirst = 1..^0; // the indices from `1` to `N-1` var dropLast = 0..^1; // the indices from `0` to `N-2` var maybeLast = ^1..6; // the indices from `N-1` to 5 var lastTwo = ^2..^0; // the indices from `N-2` to `N-1`przykład końcowy
Operandy elementu .. są opcjonalne, a pierwsze wartości domyślne to 0, a druga wartość domyślna to ^0.
Przykład
Pięć z powyższych przykładów można skrócić, opierając się na wartościach domyślnych dla operandów:
var firstQuad = ..4; // the indices from `0` to `3` var wholeSeq = ..; // the indices from `0` to `N-1` var dropFirst = 1..; // the indices from `1` to `N-1` var dropLast = ..^1; // the indices from `0` to `N-2` var lastTwo = ^2..; // the indices from `N-2` to `N-1`przykład końcowy
Range Wartość jest prawidłowa w odniesieniu do długości L, jeśli:
- indeksy betonowe w odniesieniu do L
RangewłaściwościStartiEndznajdują się w zakresie od 0 do L; - indeks betonowy dla
Startelementu nie jest większy niż indeks betonowy dlaEnd
Metoda GetOffsetAndLength z argumentem length konwertuje wartość abstrakcyjną Range na konkretną Range wartość reprezentowaną przez krotkę. Jeśli element Range jest nieprawidłowy w odniesieniu do length metody zgłasza wartość ArgumentOutOfRangeException.
Zwrócona Range krotka jest parą formy (S, N) , w której:
-
Sjest początkowym przesunięciem zakresu, czyli indeksem dlaStartwłaściwościRange; i -
Njest liczbą elementów w zakresie, czyli różnicą między konkretnymi indeksami właściwościEndiStart; - obie wartości są obliczane w odniesieniu do
lengthwartości .
Wartość konkretnego zakresu jest pusta , jeśli N jest równa zero. Pusty zakres betonowy może mieć wartość równą S konkretnemu indeksowi przeszłości (§18.1), może nie być pustym zakresem. Gdy element Range używany do fragmentowania (§18.1) kolekcja jest prawidłowa i pusta w odniesieniu do tej kolekcji, wówczas wynikowy wycinek jest pustą kolekcją.
Nuta: Konsekwencją powyższego jest to, że
Rangewartość, która jest prawidłowa i pusta w odniesieniu dolengthzera, może służyć do wycinka pustej kolekcji i powoduje pusty wycinek. Różni się to od indeksowania, które zgłasza wyjątek, jeśli kolekcja jest pusta. notatka końcowa*
Przykład
Za pomocą powyższych zmiennych z elementem
GetOffSetAndLength(6):var (ix0, len0) = firstQuad.GetOffsetAndLength(6); // ix0 = 0, len0 = 4 var (ix1, len1) = nextQuad.GetOffsetAndLength(6); // throws // ArgumentOutOfRangeException as range crosses sequence end var (ix2, len2) = wholeSeq.GetOffsetAndLength(6); // ix2 = 0, len2 = 6 var (ix3, len3) = dropFirst.GetOffsetAndLength(6); // ix3 = 1, len3 = 5 var (ix4, len4) = dropLast.GetOffsetAndLength(6); // ix4 = 0, len4 = 5 var (ix5, len5) = maybeLast.GetOffsetAndLength(6); // ix5 = 5, len5 = 1 var (ix6, len6) = lastTwo.GetOffsetAndLength(6); // ix6 = 4, len6 = 2
Range implementuje IEquatable<Range> i wartości można porównać pod kątem równości na podstawie wartości abstrakcyjnej; dwie Range wartości są równe, jeśli i tylko wtedy, gdy wartości abstrakcyjne odpowiednich Start właściwości i End są równe (§18.2). Jednak Range wartości nie są uporządkowane i nie są udostępniane żadne inne operacje porównania.
Nuta:
Rangewartości są nieurządkowane, ponieważ są abstrakcyjne i nie ma unikatowej relacji porządkowania. Po przekonwertowaniu na konkretny początek i długość, np. przezGetOffsetAndLengthparametr , można zdefiniować relację porządkowania. notatka końcowa
Range wartości mogą być używane bezpośrednio w argument_list wyrażenia element_access (§12.8.12), czyli:
- dostęp do tablicy, a obiekt docelowy jest tablicą jednowymiarową (§12.8.12.2);
- dostęp do ciągu (§12.8.12.3);
- dostęp indeksatora i typ docelowy ma indeksator z odpowiednimi parametrami
Rangetypu (§12.8.12.4) lub typu, do któregoRangewartości są niejawnie konwertowane; lub - dostęp indeksatora (§12.8.12.4) i typ docelowy jest zgodny ze wzorcem sekwencji, dla którego określono niejawną
Rangeobsługę (§18.4.3).
18.4 Niejawna obsługa wzorca dla indeksów i zakresów
18.4.1 Ogólne
Jeśli wyrażenie element_access (§12.8.12) formularza E[A]; gdzie E ma typ T i A jest pojedynczym wyrażeniem niejawnie konwertowanym na Index lub Range; nie można zidentyfikować jako:
- dostęp do tablicy (§12.8.12.2),
- dostęp do ciągu (§12.8.12.3) lub
- dostęp indeksatora (§12.8.12.4), ponieważ
Tnie zapewnia odpowiedniego indeksatora dostępnego
następnie zapewniana jest niejawna obsługa wyrażenia, jeśli T jest zgodna z określonym wzorcem. Jeśli T ten wzorzec nie jest zgodny, wystąpi błąd czasu kompilacji.
Obsługa niejawnego indeksu w wersji 18.4.2
Jeśli w jakimkolwiek kontekście wyrażenie element_access (§12.8.12) formularza E[A]; gdzie E ma typ T i A jest jedno wyrażenie niejawnie konwertowane na Index; jest nieprawidłowe (§18.4.1), jeśli w tym samym kontekście:
-
Tzapewnia dostępnym członkom kwalifikującym go jako sekwencję (§18.1); i - wyrażenie
E[0]jest prawidłowe i używa tego samego indeksatora, który kwalifikuje sięTjako sekwencja
następnie wyrażenie E[A] jest niejawnie wspierane.
Bez ograniczania w inny sposób implementacji niniejszego standardu kolejność obliczania wyrażenia jest równoważna:
-
Ejest obliczany; -
Ajest obliczany; - właściwość zliczana
Tjest obliczana, jeśli jest to wymagane przez implementację; - metodę pobierania lub ustawiania metody
intindeksatora opartegoTna tym, który będzie używanyE[0]w tym samym kontekście, jest wywoływany.
Obsługa niejawnego zakresu 18.4.3
Jeśli w jakimkolwiek kontekście wyrażenie element_access (§12.8.12) formularza E[A]; gdzie E ma typ T i A jest jedno wyrażenie niejawnie konwertowane na Range; jest nieprawidłowe (§18.4.1), jeśli w tym samym kontekście:
-
Tudostępnia dostępne elementy członkowskie kwalifikujące go jako liczalne i fragmentowalne (§18.1)
następnie wyrażenie E[A] jest niejawnie wspierane.
Bez ograniczania w inny sposób implementacji niniejszego standardu kolejność obliczania wyrażenia jest równoważna:
-
Ejest obliczany; -
Ajest obliczany; - właściwość zliczana
Tjest obliczana, jeśli jest to wymagane przez implementację; -
Slicemetoda jest wywoływanaT.
ECMA C# draft specification