Bagikan melalui


18 Pengindeksan dan pemotongan yang diperluas

18.1 Umum

Klausul ini memperkenalkan model untuk jenis koleksiyang dapat diindeks dan dapat dipoting yang diperluas yang dibangun di atas:

  • Jenis yang diperkenalkan dalam klausul ini, System.Index (§18.2) dan System.Range (§18.3);
  • Operator unary ^ (§12.9.6) dan biner .. (§12.10) yang telah ditentukan sebelumnya; dan
  • Ekspresi element_access .

Di bawah model, jenis diklasifikasikan sebagai:

  • koleksi jika mewakili sekelompok elemens
  • koleksi yang dapat diindeks yang diperluas jika mendukung ekspresi element_access yang memiliki ekspresi argumen tunggal dari jenis Index yang mengembalikan dan/atau mengatur elemen tunggal dari jenis, baik berdasarkan nilai atau berdasarkan referensi; dan
  • koleksi yang dapat dipoting yang diperluas jika mendukung ekspresi element_access yang memiliki ekspresi argumen tunggal dari jenis Range yang mengembalikan iringan elemen dari jenis menurut nilai.

Catatan: Model tidak mengharuskan ikhian jenis dapat diatur, tetapi jenis dapat mendukungnya sebagai ekstensi model. catatan akhir

Model ini didukung untuk array dimensi tunggal (§12.8.12.2) dan string (§12.8.12.3).

Model ini dapat didukung oleh kelas, struct, atau jenis antarmuka apa pun yang menyediakan pengindeks yang sesuai (§15.9) yang mengimplementasikan semantik model.

Dukungan implisit untuk model disediakan untuk jenis yang tidak secara langsung mendukungnya tetapi yang menyediakan pola anggota tertentu (§18.4). Dukungan ini berbasis pola, bukan berbasis semantik, karena semantik anggota jenis di mana berbasisnya diasumsikan - bahasa tidak memberlakukan, atau memeriksa, semantik dari anggota jenis ini.

Untuk tujuan klausul ini, istilah-istilah berikut didefinisikan:

  • Koleksi adalah jenis yang mewakili sekelompok elemen.
  • Koleksi yang dapat dihitung adalah koleksi yang menyediakan properti yang dapat dihitung properti intinstans bernilai yang nilainya adalah jumlah elemen yang saat ini berada dalam grup. Properti ini akan diberi nama baik Length atau Count. Yang pertama dipilih jika keduanya ada.
  • Urutan ataujenis yang dapat diindeks adalah koleksi:
    • yang dapat dihitung;
    • di mana setiap elemen dapat diakses menggunakan ekspresi element_access dengan satu argumen yang diperlukan int , indeks dari awal, argumen opsional tambahan diizinkan;
    • urutan dapat dimodifikasi jika setiap elemen juga dapat diatur menggunakan ekspresi element_access ;
    • indeks dari awal elemen adalah jumlah elemen sebelum dalam urutan, untuk urutan yang berisi elemen N :
      • elemen pertama dan terakhir masing-masing memiliki indeks 0 dan N-1, dan
      • indeks past-end, indeks yang mewakili elemen hipotetis setelah yang terakhir, memiliki nilai N.
  • Indeks dari ujung mewakili posisi elemen dalam urutan relatif terhadap indeks akhir. Untuk urutan yang berisi elemen N , indeks pertama, terakhir, dan akhir masing-masing adalah N, 1 dan 0.
  • Rentang adalah eksekusi yang berdekatan dari nol atau lebih indeks yang dimulai pada indeks apa pun dalam urutan.
  • Ikatan adalah kumpulan elemen dalam rentang.
  • Koleksi yang dapat dipoting adalah koleksi yang:
    • dapat dihitung;
    • menyediakan metode Slice yang mengambil dua int parameter yang menentukan rentang, menjadi indeks awal dan hitungan elemen masing-masing, dan mengembalikan ikatan baru yang dibangun dari elemen dalam rentang.

Definisi di atas diperluas untuk penggunaan Index dan Range sebagai berikut:

  • Jenis juga merupakan urutan jika ekspresi element_access mengambil satu argumen yang diperlukan Index , bukan int argumen, didukung. Jika perbedaan diperlukan, jenisnya disebut dapat diindeks diperpanjang.
  • Jenis juga dapat dipoting jika ekspresi element_access mengambil satu argumen yang diperlukan Range , bukan Slice metode, didukung. Jika perbedaan diperlukan, jenisnya disebut extended sliceable.

Apakah jenis diklasifikasikan sebagai dapat dihitung, dapat diindeks, atau dapat dipotok tunduk pada batasan aksesibilitas anggota (§7,5) dan oleh karena itu bergantung pada di mana jenis tersebut digunakan.

Contoh: Jenis di mana properti dan/atau pengindeks yang protected dapat dihitung hanya merupakan urutan untuk anggota itu sendiri dan jenis turunan apa pun. contoh akhir

Anggota yang diperlukan untuk jenis yang memenuhi syarat sebagai urutan atau dapat diiris dapat diwariskan.

Contoh: Dalam kode berikut

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) { … }
}

Jenisnya A dapat dihitung, B adalah urutan, dan C dapat dipoting dan urutannya.

contoh akhir

Note:

  • Jenis dapat dipoting tanpa dapat diindeks karena kurangnya pengindeks (dapat diakses).
  • Agar jenis dapat dipoting dan/atau dapat diindeks memerlukan jenis yang dapat dihitung.
  • Meskipun elemen urutan diurutkan berdasarkan posisi dalam urutan, elemen itu sendiri tidak perlu diurutkan berdasarkan nilainya, atau bahkan dapat diurutkan.

catatan akhir

18.2 Jenis indeks

Jenis mewakili System.Index indeks abstrak yang mewakili indeks dari awal atau indeks dari ujung.

    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 nilai dibangun dari int, menentukan offset non-negatif, dan bool, yang menunjukkan apakah offset berasal dari akhir (true) atau mulai (false). Jika offset yang ditentukan negatif ArgumentOutOfRangeException , maka akan dilemparkan.

Example

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 ArgumentOutOfRangeException

contoh akhir

Ada konversi implisit dari intIndex mana menghasilkan indeks dari awal, dan operator ^ unary yang ditentukan bahasa (§12.9.6) dari intIndex mana menghasilkan indeks dari akhir.

Example

Menggunakan konversi implisit dan operator unary ^ contoh di atas dapat ditulis:

Index first = 0; // first element index
var last = ^1;   // last element index
var past = ^0;   // past-end index

contoh akhir

Metode GetOffset ini mengonversi dari nilai abstrak Index ke nilai indeks konkret int untuk urutan yang ditentukan length. Index Jika nilai, I, adalah dari akhir metode ini mengembalikan nilai yang sama dengan length - I.Value, jika tidak, nilai yang sama I.Valuedengan .

Metode ini tidak memeriksa bahwa nilai yang dikembalikan berada dalam rentang yang valid melalui 0length-1 inklusif.

Nota: Tidak ada pemeriksaan yang ditentukan sebagai penggunaan hasil yang diharapkan adalah mengindeks ke dalam urutan dengan length elemen, dan bahwa operasi pengindeksan diharapkan untuk melakukan pemeriksaan yang sesuai. catatan akhir

Index implementasi IEquatable<Index> dan nilai dapat dibandingkan untuk kesetaraan berdasarkan nilai abstrak; dua Index nilai sama jika dan hanya jika masing-masing Value dan IsFromEnd properti sama. Namun Index nilai tidak diurutkan dan tidak ada operasi perbandingan lain yang disediakan.

Nota:Index nilai tidak diurutkan karena indeks abstrak, secara umum tidak mungkin untuk menentukan apakah indeks dari ujung datang sebelum atau sesudah indeks dari awal tanpa mengacu pada panjang urutan. Setelah dikonversi ke indeks konkret, misalnya oleh GetOffset, indeks konkret tersebut sebanding. catatan akhir

Index nilai dapat langsung digunakan dalam argument_list ekspresi element_access (§12.8.12) yaitu:

  • akses array dan target adalah array dimensi tunggal (§12.8.12.2);
  • akses string (§12.8.12.3)
  • akses pengindeks dan jenis target memiliki pengindeks dengan parameter yang sesuai dari salah satu Index jenis (§12.8.12.4) atau dari jenis yang Index nilainya secara implisit dapat dikonversi; atau
  • akses pengindeks dan jenis target sesuai dengan pola urutan yang dukungan implisitnya Index ditentukan (§18.4.2).

18.3 Jenis rentang

Jenis mewakili System.Range rentang Indexabstrak es dari Start indeks hingga, tetapi tidak termasuk, End indeks.

    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 nilai dibangun dari dua Index nilai.

Example

Contoh berikut menggunakan konversi implisit dari int ke Index (§18.2) dan ^ operator (§12.9.6) untuk membuat Index nilai untuk masing-masing Range:

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`

contoh akhir

Operator .. yang ditentukan bahasa (§12.10) membuat Range nilai dari Index nilai.

Example

.. Menggunakan operator contoh di atas dapat ditulis:

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`

contoh akhir

Operan bersifat .. opsional, default pertama ke 0, default kedua ke ^0.

Example

Lima contoh di atas dapat disingkat dengan mengandalkan nilai default untuk operand:

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`

contoh akhir

Nilai Rangevalid sehubungan dengan panjang L jika:

  • indeks konkret sehubungan dengan L properti RangeStart dan End berada dalam rentang 0 hingga L; dan
  • indeks beton untuk Start tidak lebih besar dari indeks beton untuk End

Metode GetOffsetAndLength dengan argumen length mengonversi nilai abstrak Range menjadi nilai konkret Range yang diwakili oleh tuple. Range Jika tidak valid sehubungan length dengan metode melemparkan ArgumentOutOfRangeException.

Tuple beton Range yang dikembalikan adalah sepasang bentuk (S, N) di mana:

  • S adalah offset awal dari rentang, menjadi indeks konkret untuk Start properti Range; dan
  • N adalah jumlah item dalam rentang, menjadi perbedaan antara indeks konkret untuk End properti dan Start ;
  • kedua nilai dihitung sehubungan lengthdengan .

Nilai rentang beton kosong jika N nol. Rentang beton kosong mungkin memiliki nilai yang S sama dengan indeks akhir beton (§18,1), rentang yang tidak kosong mungkin tidak. Range Ketika yang digunakan untuk mengpotong (§18.1) koleksi valid dan kosong sehubungan dengan koleksi tersebut, maka iringan yang dihasilkan adalah koleksi kosong.

Nota: Konsekuensi dari hal di atas adalah bahwa Range nilai yang valid dan kosong sehubungan length dengan nol dapat digunakan untuk menggoreng koleksi kosong dan menghasilkan iringan kosong. Ini berbeda dari pengindeksan yang melempar pengecualian jika koleksi kosong. catatan akhir*

Example

Menggunakan variabel yang ditentukan di atas dengan 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 implementasi IEquatable<Range> dan nilai dapat dibandingkan untuk kesetaraan berdasarkan nilai abstrak; dua Range nilai sama jika dan hanya jika nilai abstrak masing-masing Start dan End properti sama (§18,2). Namun Range nilai tidak diurutkan dan tidak ada operasi perbandingan lain yang disediakan.

Nota:Range nilai tidak diurutkan baik karena abstrak dan tidak ada hubungan pengurutan yang unik. Setelah dikonversi ke awal dan panjang beton, misalnya dengan GetOffsetAndLength, hubungan pemesanan dapat ditentukan. catatan akhir

Range nilai dapat langsung digunakan dalam argument_list ekspresi element_access (§12.8.12) yaitu:

  • akses array dan target adalah array dimensi tunggal (§12.8.12.2);
  • akses string (§12.8.12.3);
  • akses pengindeks dan jenis target memiliki pengindeks dengan parameter yang sesuai dari salah satu Range jenis (§12.8.12.4) atau dari jenis yang Range nilainya secara implisit dapat dikonversi; atau
  • akses pengindeks (§12.8.12.4) dan jenis target sesuai dengan pola urutan yang dukungan implisitnya Range ditentukan (§18.4.3).

18.4 Dukungan implisit berbasis pola untuk Indeks dan Rentang

18.4.1 Umum

Jika ekspresi element_access (§12.8.12) formulir E[A]; di mana E memiliki jenis T dan A merupakan ekspresi tunggal yang secara implisit dapat dikonversi ke Index atau Range; gagal diidentifikasi sebagai:

lalu dukungan implisit untuk ekspresi disediakan jika T sesuai dengan pola tertentu. Jika T tidak sesuai dengan pola ini, maka terjadi kesalahan waktu kompilasi.

18.4.2 Dukungan Indeks Implisit

Jika dalam konteks apa pun ekspresi element_access (§12.8.12) formulir E[A]; di mana E memiliki jenis T dan A merupakan ekspresi tunggal yang secara implisit dapat dikonversi ke Index; tidak valid (§18.4.1) maka jika dalam konteks yang sama:

  • T menyediakan anggota yang dapat diakses memenuhi syarat sebagai urutan (§18.1); dan
  • ekspresi E[0] valid dan menggunakan pengindeks yang sama yang memenuhi syarat T sebagai urutan

maka ekspresi E[A] harus didukung secara implisit.

Tanpa membatasi implementasi Standar ini urutan evaluasi ekspresi harus setara dengan:

  1. E dievaluasi;
  2. A dievaluasi;
  3. properti yang T dapat dihitung dievaluasi, jika diperlukan oleh implementasi;
  4. mendapatkan atau mengatur aksesor pengindeks intT berbasis yang akan digunakan oleh E[0] dalam konteks yang sama dipanggil.

18.4.3 Dukungan Rentang Implisit

Jika dalam konteks apa pun ekspresi element_access (§12.8.12) formulir E[A]; di mana E memiliki jenis T dan A merupakan ekspresi tunggal yang secara implisit dapat dikonversi ke Range; tidak valid (§18.4.1) maka jika dalam konteks yang sama:

  • T menyediakan anggota yang dapat diakses memenuhi syarat sebagai dapat dihitung dan dapat dipoting (§18.1)

maka ekspresi E[A] harus didukung secara implisit.

Tanpa membatasi implementasi Standar ini urutan evaluasi ekspresi harus setara dengan:

  1. E dievaluasi;
  2. A dievaluasi;
  3. properti yang T dapat dihitung dievaluasi, jika diperlukan oleh implementasi;
  4. Slice metode T dipanggil.