Bagikan melalui


Ekspresi koleksi - Referensi bahasa C#

Anda dapat menggunakan ekspresi koleksi untuk membuat nilai koleksi umum. Ekspresi koleksi adalah sintaks terse yang, saat dievaluasi, dapat ditetapkan ke berbagai jenis koleksi. Ekspresi koleksi berisi urutan elemen antara [ dan ] tanda kurung siku. Contoh berikut mendeklarasikan System.Span<T> elemen string dan menginisialisasinya ke hari dalam seminggu:

Span<string> weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
foreach (var day in weekDays)
{
    Console.WriteLine(day);
}

Ekspresi koleksi dapat dikonversi ke berbagai jenis koleksi. Contoh pertama menunjukkan cara menginisialisasi variabel menggunakan ekspresi koleksi. Kode berikut menunjukkan banyak lokasi lain di mana Anda bisa menggunakan ekspresi koleksi:

// Initialize private field:
private static readonly ImmutableArray<string> _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

// property with expression body:
public IEnumerable<int> MaxDays =>
    [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

public int Sum(IEnumerable<int> values) =>
    values.Sum();

public void Example()
{
    // As a parameter:
    int sum = Sum([1, 2, 3, 4, 5]);
}

Anda tidak dapat menggunakan ekspresi koleksi di mana konstanta waktu kompilasi diharapkan, seperti menginisialisasi konstanta, atau sebagai nilai default untuk argumen metode.

Kedua contoh sebelumnya menggunakan konstanta sebagai elemen ekspresi koleksi. Anda juga dapat menggunakan variabel untuk elemen seperti yang ditunjukkan dalam contoh berikut:

string hydrogen = "H";
string helium = "He";
string lithium = "Li";
string beryllium = "Be";
string boron = "B";
string carbon = "C";
string nitrogen = "N";
string oxygen = "O";
string fluorine = "F";
string neon = "Ne";
string[] elements = [hydrogen, helium, lithium, beryllium, boron, carbon, nitrogen, oxygen, fluorine, neon];
foreach (var element in elements)
{
    Console.WriteLine(element);
}

Menyebarkan elemen

Anda menggunakan elemen.. spread untuk menyebarkan nilai koleksi dalam ekspresi koleksi. Contoh berikut membuat koleksi untuk alfabet lengkap dengan menggabungkan koleksi vokal, koleksi konsonan, dan huruf "y", yang dapat berupa:

string[] vowels = ["a", "e", "i", "o", "u"];
string[] consonants = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
                       "n", "p", "q", "r", "s", "t", "v", "w", "x", "z"];
string[] alphabet = [.. vowels, .. consonants, "y"];

Elemen ..vowelsspread , ketika dievaluasi, menghasilkan lima elemen: "a", , "e", "i""o", dan "u". Elemen ..consonants spread menghasilkan 20 elemen, angka dalam consonants array. Variabel dalam elemen spread harus dapat dijumlahkan menggunakan foreach pernyataan. Seperti yang ditunjukkan pada contoh sebelumnya, Anda dapat menggabungkan elemen spread dengan elemen individual dalam ekspresi koleksi.

Konversi

Ekspresi koleksi dapat dikonversi ke jenis koleksi yang berbeda, termasuk:

Penting

Ekspresi koleksi selalu membuat koleksi yang menyertakan semua elemen dalam ekspresi koleksi, terlepas dari jenis target konversi. Misalnya, ketika target konversi adalah System.Collections.Generic.IEnumerable<T>, kode yang dihasilkan mengevaluasi ekspresi koleksi dan menyimpan hasilnya dalam koleksi dalam memori.

Perilaku ini berbeda dari LINQ, di mana urutan mungkin tidak dibuat sampai dijumlahkan. Anda tidak dapat menggunakan ekspresi koleksi untuk menghasilkan urutan tak terbatas yang tidak akan dijumlahkan.

Pengkompilasi menggunakan analisis statis untuk menentukan cara paling berkinerja untuk membuat koleksi yang dideklarasikan dengan ekspresi koleksi. Misalnya, ekspresi koleksi kosong, [], dapat direalisasikan seolah-olah Array.Empty<T>() target tidak akan dimodifikasi setelah inisialisasi. Ketika target adalah System.Span<T> atau System.ReadOnlySpan<T>, penyimpanan mungkin dialokasikan tumpukan. Spesifikasi fitur ekspresi koleksi menentukan aturan yang harus diikuti pengkompilasi.

Banyak API kelebihan beban dengan beberapa jenis koleksi sebagai parameter. Karena ekspresi koleksi dapat dikonversi ke berbagai jenis ekspresi, API ini mungkin memerlukan transmisi pada ekspresi koleksi untuk menentukan konversi yang benar. Aturan konversi berikut menyelesaikan beberapa ambiguitas:

  • Konversi ke Span<T>, ReadOnlySpan<T>, atau jenis lain ref struct lebih baik daripada konversi ke jenis struct non-ref.
  • Konversi ke jenis noninterface lebih baik daripada konversi ke jenis antarmuka.

Saat ekspresi koleksi dikonversi ke Span atau , konteks aman objek rentang diambil dari konteks aman semua elemen yang disertakan ReadOnlySpandalam rentang. Untuk aturan terperinci, lihat Spesifikasi ekspresi koleksi.

Pembuat koleksi

Ekspresi koleksi berfungsi dengan jenis koleksi apa pun yang berulah dengan baik. Koleksi yang ber perilaku baik memiliki karakteristik berikut:

  • Nilai Count atau Length pada koleksi yang dapat dihitung menghasilkan nilai yang sama dengan jumlah elemen saat dijumlahkan.
  • Jenis di System.Collections.Generic namespace dianggap bebas efek samping. Dengan demikian, pengkompilasi dapat mengoptimalkan skenario di mana jenis tersebut dapat digunakan sebagai nilai perantara, tetapi sebaliknya tidak diekspos.
  • Panggilan ke beberapa anggota yang berlaku .AddRange(x) pada koleksi akan menghasilkan nilai akhir yang sama seperti iterasi dan x menambahkan semua nilai enumerasinya satu per satu ke koleksi dengan .Add.

Semua jenis koleksi dalam runtime .NET berperilaku baik.

Peringatan

Jika jenis koleksi kustom tidak bersifat baik, perilaku saat Anda menggunakan jenis koleksi tersebut dengan ekspresi koleksi tidak terdefinisi.

Jenis Anda memilih untuk mengumpulkan dukungan ekspresi dengan menulis Create() metode dan menerapkan System.Runtime.CompilerServices.CollectionBuilderAttribute pada jenis koleksi untuk menunjukkan metode penyusun. Misalnya, pertimbangkan aplikasi yang menggunakan buffer panjang tetap 80 karakter. Kelas tersebut mungkin terlihat seperti kode berikut:

public class LineBuffer : IEnumerable<char>
{
    private readonly char[] _buffer = new char[80];

    public LineBuffer(ReadOnlySpan<char> buffer)
    {
        int number = (_buffer.Length < buffer.Length) ? _buffer.Length : buffer.Length;
        for (int i = 0; i < number; i++)
        {
            _buffer[i] = buffer[i];
        }
    }

    public IEnumerator<char> GetEnumerator() => _buffer.AsEnumerable<char>().GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _buffer.GetEnumerator();

    // etc
}

Anda ingin menggunakannya dengan ekspresi koleksi seperti yang diperlihatkan dalam sampel berikut:

LineBuffer line = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'];

Jenis mengimplementasikan LineBufferIEnumerable<char>, sehingga pengkompilasi mengenalinya sebagai kumpulan char item. Parameter jenis antarmuka yang diimplementasikan System.Collections.Generic.IEnumerable<T> menunjukkan jenis elemen. Anda perlu membuat dua tambahan ke aplikasi Anda untuk dapat menetapkan ekspresi koleksi ke LineBuffer objek. Pertama, Anda perlu membuat kelas yang berisi Create metode:

internal static class LineBufferBuilder
{
    internal static LineBuffer Create(ReadOnlySpan<char> values) => new LineBuffer(values);
}

Metode Create harus mengembalikan LineBuffer objek, dan harus mengambil satu parameter dari jenis ReadOnlySpan<char>. Parameter ReadOnlySpan jenis harus cocok dengan jenis elemen koleksi. Metode penyusun yang mengembalikan koleksi generik akan memiliki generik ReadOnlySpan<T> sebagai parameternya. Metode harus dapat diakses dan static.

Terakhir, Anda harus menambahkan CollectionBuilderAttribute ke LineBuffer deklarasi kelas:

[CollectionBuilder(typeof(LineBufferBuilder), "Create")]

Parameter pertama menyediakan nama kelas Builder . Atribut kedua menyediakan nama metode penyusun.