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 ..vowels
beş öğ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:
- System.Span<T> ve System.ReadOnlySpan<T>.
- Diziler.
- Parametre türü koleksiyon ifade türünden
ReadOnlySpan<T>
öğesine örtük dönüştürme olan create yöntemine sahip herhangi bir türT
. - Koleksiyon başlatıcıyı destekleyen herhangi bir tür, örneğinSystem.Collections.Generic.List<T>. Bu gereksinim genellikle türün desteklediği System.Collections.Generic.IEnumerable<T> ve koleksiyona öğe eklemek için erişilebilir
Add
bir yöntem olduğu anlamına gelir. Koleksiyon ifadesi öğelerinin türünden koleksiyonun öğe türüne örtük bir dönüştürme olmalıdır. Yayma öğeleri için, spread öğesinin türünden koleksiyonun öğe türüne örtük bir dönüştürme olmalıdır. - Aşağıdaki arabirimlerden herhangi biri:
Ö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 Span
ReadOnlySpan
öğ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ğerex
.Add
neden 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 static
eriş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.