Tanımlama kümeleri ve yapısızlaştırma

Tavsiye

Yazılım geliştirme konusunda yeni misiniz? Başlangıç öğreticileriyle işe başlayın. Bir yöntemden birden çok değer döndürmeniz veya adlandırılmış bir tür oluşturmadan değerleri gruplamanız gerektiğinde, demetlerle karşılaşırsınız.

Başka bir dilde mi deneyimlisiniz? C# tanımlama kümeleri, Python veya Swift'teki tanımlama demetlerine benzer ancak isteğe bağlı adlandırılmış öğeler ve tam yapısızlaştırma desteğine sahip değer türleridir. C#'ye özgü desenler için yapısızlaştırma ve eşitlik bölümlerine hızlıca göz atın.

Tuple, adlandırılmış bir tür tanımlamanıza gerek kalmadan, birden çok değeri tek ve hafif bir yapıda gruplandırır. Tuple'lar, yerinde bildirebileceğiniz, yöntemlerden döndürebileceğiniz ve bireysel değişkenlere ayrıştırabileceğiniz değer türleridir. İlgili değerleri hızlı ve geçici bir şekilde gruplamanız gerektiğinde demetleri kullanın. Örneğin, bir yöntemden birden çok sonuç döndürdiğinizde veya bir koordinat çifti depoladığınızda.

Aşağıdaki örnek, adlandırılmış öğelerle bir demet oluşturur ve her öğeye ada göre erişir.

var location = (Latitude: 47.6062, Longitude: -122.3321);
Console.WriteLine($"Location: {location.Latitude}, {location.Longitude}");
// Output: Location: 47.6062, -122.3321

Tuple'lar, bir sınıf, yapı veya kayıt tanımlamanın gereksiz bir formalite eklediği kısa ömürlü gruplandırmalar için iyi çalışır. Uzun süreli etki alanı kavramları veya davranışları olan türler için kayıtları, sınıfları veya yapıları tercih edin. Her birinin ne zaman kullanılacağının karşılaştırması için bkz. Hangi tür türünü seçme.

Tuple'ları bildirme ve başlatma

Bir demet, öğe türlerini parantez içinde listeleyerek tanımlayın. İsteğe bağlı olarak kodu daha okunabilir hale getirmek için her öğeyi adlandırabilirsiniz:

// Tuple with named elements
(string Name, int Age) person = ("Alice", 30);
Console.WriteLine($"{person.Name} is {person.Age} years old");

// Tuple with default element names (Item1, Item2)
(string, int) unnamed = ("Bob", 25);
Console.WriteLine($"{unnamed.Item1} is {unnamed.Item2} years old");

// Tuple declared with var and inline names
var city = (Name: "Seattle", Population: 749_256);
Console.WriteLine($"{city.Name}: population {city.Population}");

Ad sağlamadığınızda, öğeler varsayılan adları Item1, Item2vb. kullanır. Adlandırılmış öğeler, ayrı bir tür tanımı gerektirmeden kodunuzu kendi kendine belgelemenizi sağlar.

Çıkarsanan öğe adları

Derleyici, tuple'ı başlatırken kullandığınız değişken adları veya özellik adlarından öğe adlarını çıkarır. Bu özellik, adlar eşleştiğinde yedekliliği önler:

var name = "Carol";
var age = 28;

// The compiler infers element names from the variable names
var person = (name, age);
Console.WriteLine($"{person.name} is {person.age}");
// Output: Carol is 28

Çıkarsanan adlar kodunuzu kısa tutar. Farklı bir öğe adına ihtiyacınız varsa, bunu açıkça belirtin.

Bir yöntemden birden çok değer döndürme

Tüplerin en yaygın kullanımlarından biri, bir fonksiyondan birden çok değer döndürmektir. Sınıf tanımlamak veya out parametreleri kullanmak yerine, adlandırılmış öğeler içeren bir demet döndürebilirsiniz.

static (double Minimum, double Maximum, double Average) ComputeStats(List<double> values)
{
    var min = values.Min();
    var max = values.Max();
    var avg = values.Average();
    return (min, max, avg);
}

Adlandırılmış tuple öğeleri, dönüş değerlerini hem çağrı yerinde hem de yöntem imzasında okunabilir hale getirir. Çağıran, konum sırasını hatırlamaya gerek kalmadan her değere ada göre erişebilir.

Demetleri parçalama

Yapısızlaştırma, bir demetin öğelerini tek bir ifadede ayrı değişkenlere ayırır. Demetleri çeşitli şekillerde parçalayabilirsiniz.

var point = (X: 3, Y: 7);

// Deconstruct with var (infer all types)
var (x, y) = point;
Console.WriteLine($"x={x}, y={y}");

// Deconstruct with explicit types
(int px, int py) = point;
Console.WriteLine($"px={px}, py={py}");

// Deconstruct into existing variables
int a, b;
(a, b) = point;
Console.WriteLine($"a={a}, b={b}");

// Deconstruct a method return value directly
List<double> data = [10.0, 20.0, 30.0];
var (min, max, avg) = ComputeStats(data);
Console.WriteLine($"Min: {min}, Max: {max}, Avg: {avg}");

Bir yöntem çağrısından bir demet aldığınızda ve hemen içindeki bireysel değerlerle çalışmanız gerektiğinde, yapısızlaştırma özellikle yararlıdır.

Tuples'ları doğrudan foreach döngülerinde dekonstürükte edebilirsiniz, bu da gruplanmış değer koleksiyonları üzerinde yinelemeyi kısaltır.

List<(string Name, int Score)> results =
[
    ("Alice", 92),
    ("Bob", 87),
    ("Carol", 95)
];

foreach (var (name, score) in results)
{
    Console.WriteLine($"{name}: {score}");
}

Her öğeye ihtiyacınız olmadığında, yok saymak istediğiniz her değerin yerine bir discard (_) kullanın. Atılan her konum için ayrı bir _ kullanın.

List<double> values = [5.0, 10.0, 15.0];
var (_, max, _) = ComputeStats(values);
Console.WriteLine($"Only need the max: {max}");
// Output: Only need the max: 15

Farklı bağlamlarda Atmaları kullanma hakkında daha fazla bilgi için bkz.

Tanımlama grubu eşitliği

Demetleri == ve != kullanarak karşılaştırabilirsiniz. Bu işleçler her öğeyi sırayla karşılaştırır, dolayısıyla iki demet, karşılık gelen tüm öğeleri eşit olduğunda birbirine eşit olur.

var order1 = (Product: "Widget", Quantity: 5);
var order2 = (Product: "Widget", Quantity: 5);
var order3 = (Product: "Gadget", Quantity: 3);

Console.WriteLine(order1 == order2); // True
Console.WriteLine(order1 == order3); // False

// Element names don't affect equality—only values matter
var named = (X: 1, Y: 2);
var different = (A: 1, B: 2);
Console.WriteLine(named == different); // True

Demet eşitliği, her öğe türü üzerinde tanımlanan == işleci kullanır, bu da karşılaştırmanın dizeler, sayılar ve == tanımlayan diğer türler için doğru çalıştığı anlamına gelir. Öğe adları eşitliği etkilemez; yalnızca değerler ve konumlar önemlidir.

Yıkıcı olmayan mutasyon with ile

with ifadesi, bir veya daha fazla elemanı değiştirilmiş bir tüple kopyası oluşturur ve özgün tüple olduğu gibi kalır.

var original = (Name: "Widget", Price: 19.99m, InStock: true);
var discounted = original with { Price = 14.99m };

Console.WriteLine($"Original: {original.Name} at {original.Price:C}");
Console.WriteLine($"Discounted: {discounted.Name} at {discounted.Price:C}");
// Output:
// Original: Widget at $19.99
// Discounted: Widget at $14.99

Bu düzen, var olan bir demetin orijinalini değiştirmeden farklı bir şekilini istediğinizde kullanışlıdır. İfade, withkayıtlarda olduğu gibi tanımlama listelerinde de aynı şekilde çalışır.

Sözlüklerdeki ve aramalardaki tanımlama kümeleri

Bir anahtarı birden fazla veri parçasıyla ilişkilendirmeniz gerektiğinde, demetler faydalı sözlük değerleri oluşturur.

var sizeChart = new Dictionary<string, (int Min, int Max)>
{
    ["Small"] = (0, 50),
    ["Medium"] = (51, 100),
    ["Large"] = (101, 200)
};

if (sizeChart.TryGetValue("Medium", out var range))
{
    Console.WriteLine($"Medium: {range.Min}–{range.Max}");
}
// Output: Medium: 51–100

Tanımlama kümeleri ayrıca sözlük anahtarları olarak da çalışır ve özel bir tür tanımlamadan bileşik anahtar sağlar. Tuples yapısal eşitlik uyguladığından, sorgular tüm öğelerin birleştirilmiş değerleriyle eşleşir.

var grid = new Dictionary<(int Row, int Column), string>
{
    [(0, 0)] = "Origin",
    [(1, 3)] = "Sensor A",
    [(2, 5)] = "Sensor B"
};

var target = (Row: 1, Column: 3);
if (grid.TryGetValue(target, out var label))
{
    Console.WriteLine($"({target.Row}, {target.Column}): {label}");
}
// Output: (1, 3): Sensor A

Bu desen, basit çok anahtarlı aramalar veya anahtardan çok değere eşlemeler için ayrı bir sınıfa ihtiyaç duymayı önler.

Tanımlama demetleri ve anonim türler karşılaştırması

Basit bir adsız veri yapısına ihtiyacınız olduğunda, tuple tercih edilen seçenektir. İfade ağacı senaryoları ve başvuru türleri gerektiren kodlar için anonim türler kullanılabilir durumda kalır, ancak tuple'lar daha iyi performans, parçalama desteği ve daha esnek sözdizimi sunar. Anonim türler hakkında daha fazla bilgi için Anonim ve demet türleri arasında seçim yapma.

Ayrıca bakınız