Koleksiyon ifadeleri - C# dil başvurusu

Ortak koleksiyon değerleri oluşturmak için koleksiyon ifadesi kullanabilirsiniz. Koleksiyon ifadesi, değerlendirildiğinde birçok farklı koleksiyon türüne atanabilen bir ters söz dizimidir. Koleksiyon ifadesi ve ] köşeli ayraçlar arasında [ bir dizi öğe içerir. Aşağıdaki örnek bir System.Span<T>string öğe bildirir ve bunları haftanın günlerine başlatır:

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

Koleksiyon ifadesi birçok farklı koleksiyon türüne dönüştürülebilir. İlk örnekte, bir koleksiyon ifadesi kullanarak bir değişkenin nasıl başlatıldığı gösterilmiştir. Aşağıdaki kod, koleksiyon ifadesi kullanabileceğiniz diğer konumların çoğunu gösterir:

// 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]);
}

Bir derleme zamanı sabitinin beklendiği bir koleksiyon ifadesi kullanamazsınız; örneğin, bir sabit başlatma veya yöntem bağımsız değişkeni için varsayılan değer olarak.

Önceki örneklerin her ikisi de koleksiyon ifadesinin öğeleri olarak sabitleri kullanıyordu. Aşağıdaki örnekte gösterildiği gibi öğeler için değişkenleri de kullanabilirsiniz:

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);
}

Spread öğesi

Bir koleksiyon ifadesindeki satır içi koleksiyon değerleri için bir spread öğesi.. kullanırsınız. Aşağıdaki örnek, ünlülerin bir koleksiyonunu, ünsüzlerin koleksiyonunu ve "y" harfini birleştirerek tam alfabe için bir koleksiyon oluşturur. Bu koleksiyonlardan biri şunlardan biri olabilir:

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"];

değerlendirildiğinde spread öğesi ..vowelsbeş öğe üretir: "a", "e", "i", "o"ve "u". Spread öğesi ..consonants dizideki consonants sayı olan 20 öğe üretir. Bir spread öğesindeki değişkenin bir foreach deyimi kullanılarak numaralandırılabilir olması gerekir. Önceki örnekte gösterildiği gibi, yayma öğelerini bir koleksiyon ifadesindeki tek tek öğelerle birleştirebilirsiniz.

Dönüşümler

Koleksiyon ifadesi , aşağıdakiler dahil olmak üzere farklı koleksiyon türlerine dönüştürülebilir:

Önemli

Koleksiyon ifadesi, dönüştürmenin hedef türünden bağımsız olarak her zaman koleksiyon ifadesindeki tüm öğeleri içeren bir koleksiyon oluşturur. Örneğin, dönüştürmenin hedefi olduğunda System.Collections.Generic.IEnumerable<T>, oluşturulan kod koleksiyon ifadesini değerlendirir ve sonuçları bellek içi bir koleksiyonda depolar.

Bu davranış LINQ'tan farklıdır; burada sıra numaralandırılana kadar örneği oluşturulamayabilir. Numaralandırılamayacak sonsuz bir dizi oluşturmak için koleksiyon ifadelerini kullanamazsınız.

Derleyici, bir koleksiyon ifadesiyle bildirilen koleksiyonu oluşturmanın en yüksek performanslı yolunu belirlemek için statik çözümleme kullanır. Örneğin, boş koleksiyon ifadesi, []hedef başlatma işleminden sonra değiştirilmeyecekmiş gibi Array.Empty<T>() gerçekleştirilebilir. Hedef veya System.Span<T>System.ReadOnlySpan<T>olduğunda, depolama alanı yığın olarak ayrılmış olabilir. Koleksiyon ifadeleri özellik belirtimi, derleyicinin izlemesi gereken kuralları belirtir.

Birçok API, parametre olarak birden çok koleksiyon türüyle aşırı yüklenir. Bir koleksiyon ifadesi birçok farklı ifade türüne dönüştürülebildiğinden, bu API'ler doğru dönüştürmeyi belirtmek için koleksiyon ifadesinde atamalar gerektirebilir. Aşağıdaki dönüştürme kuralları bazı belirsizlikleri giderir:

  • , ReadOnlySpan<T>veya başka bir ref struct türe Span<T>dönüştürme, başvuru olmayan bir yapı türüne dönüştürmeden daha iyidir.
  • Bir arabirim türüne dönüştürme, arabirim türüne dönüştürmeden daha iyidir.

Bir koleksiyon ifadesi veya SpanReadOnlySpanöğesine dönüştürüldüğünde span nesnesinin güvenli bağlamı , yayılma alanına dahil edilen tüm öğelerin güvenli bağlamından alınır. Ayrıntılı kurallar için bkz . Koleksiyon ifadesi belirtimi.

Koleksiyon oluşturucusu

Koleksiyon ifadeleri iyi davranan herhangi bir koleksiyon türüyle çalışır. İyi davranmış bir koleksiyon aşağıdaki özelliklere sahiptir:

  • Sayılabilir bir koleksiyondaki veya Length değeriCount, numaralandırıldığında öğe sayısıyla aynı değeri üretir.
  • Ad alanı içindeki türlerin System.Collections.Generic yan etkisiz olduğu varsayılır. Bu nedenle, derleyici bu tür türlerin aracı değerler olarak kullanılabileceğini ancak aksi takdirde kullanıma sunulmayabileceği senaryoları iyileştirebilir.
  • Bir koleksiyondaki bazı geçerli .AddRange(x) üyeye yapılan çağrı, yineleme ve numaralandırılmış değerlerinin tümünü ile tek tek koleksiyonuna ekleme ile aynı son değere x.Addneden olur.

.NET çalışma zamanındaki tüm koleksiyon türleri düzgün şekilde davranır.

Uyarı

Özel bir koleksiyon türü düzgün davranmıyorsa, koleksiyon ifadeleriyle bu koleksiyon türünü kullandığınızdaki davranış tanımlanmamıştır.

Türleriniz, bir Create() yöntem yazarak ve oluşturucu yöntemini belirtmek için koleksiyon türüne uygulayarak System.Runtime.CompilerServices.CollectionBuilderAttribute koleksiyon ifadesi desteğini kabul eder. Örneğin, 80 karakterlik sabit uzunlukta arabellekler kullanan bir uygulama düşünün. Bu sınıf aşağıdaki koda benzer olabilir:

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
}

Aşağıdaki örnekte gösterildiği gibi koleksiyon ifadeleriyle kullanmak istiyorsunuz:

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

türü LineBuffer uygular IEnumerable<char>, böylece derleyici bunu bir öğe koleksiyonu char olarak tanır. Uygulanan System.Collections.Generic.IEnumerable<T> arabirimin tür parametresi, öğe türünü gösterir. Bir nesneye koleksiyon ifadeleri LineBuffer atayabilmek için uygulamanıza iki ekleme yapmanız gerekir. İlk olarak, bir yöntem içeren bir Create sınıf oluşturmanız gerekir:

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

Create yöntemi bir LineBuffer nesnesi döndürmelidir ve türünde ReadOnlySpan<char>tek bir parametre almalıdır. öğesinin ReadOnlySpan tür parametresi, koleksiyonun öğe türüyle eşleşmelidir. Genel bir koleksiyon döndüren oluşturucu yönteminin parametresi genel ReadOnlySpan<T> olacaktır. yöntemine ve staticerişilebilir olması gerekir.

Son olarak, sınıf bildirimine LineBuffer öğesini CollectionBuilderAttribute eklemeniz gerekir:

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

İlk parametre Builder sınıfının adını sağlar. İkinci öznitelik, oluşturucu yönteminin adını sağlar.