Kayıt türleri oluşturma
Kayıtlar , değer tabanlı eşitlik kullanan türlerdir. C# 10, kayıtları değer türleri olarak tanımlayabilmeniz için kayıt yapıları ekler. Kayıt türü tanımları aynıysa ve her alan için her iki kayıttaki değerler eşitse, kayıt türünün iki değişkeni eşittir. Başvuruda bulunılan nesneler aynı sınıf türündeyse ve değişkenler aynı nesneye başvuruda bulunursa, sınıf türünün iki değişkeni eşittir. Değer tabanlı eşitlik, kayıt türlerinde büyük olasılıkla isteyeceğiniz diğer özellikleri ifade eder. Derleyici, yerine bir record
bildirdiğinizde bu üyelerin class
çoğunu oluşturur. Derleyici, türler için record struct
aynı yöntemleri oluşturur.
Bu öğreticide aşağıdakilerin nasıl yapılacağını öğreneceksiniz:
- Değiştiriciyi bir
class
türerecord
ekleyip eklemediğinize karar verin. - Kayıt türlerini ve konumsal kayıt türlerini bildirin.
- Kayıtlarda derleyici tarafından oluşturulan yöntemler için yöntemlerinizi değiştirmeyin.
Ön koşullar
C# 10 veya üzeri derleyici de dahil olmak üzere makinenizi .NET 6 veya üzerini çalıştıracak şekilde ayarlamanız gerekir. C# 10 derleyicisi Visual Studio 2022 veya .NET 6 SDK'sı ile başlayarak kullanılabilir.
Kayıtların özellikleri
Bir veya bildirimini değiştirerek, anahtar sözcüğüyle record
bir tür bildirerek bir class
struct
kayıt tanımlarsınız. İsteğe bağlı olarak, oluşturmak record class
için anahtar sözcüğünü class
atlayabilirsiniz. Kayıt, değer tabanlı eşitlik semantiğini izler. Değer semantiğini zorlamak için, derleyici kayıt türünüz için çeşitli yöntemler oluşturur (hem türler hem record struct
de türler içinrecord class
):
- geçersiz kılma.Object.Equals(Object)
- Parametresi kayıt türü olan bir sanal
Equals
yöntem. - geçersiz kılma.Object.GetHashCode()
- ve
operator !=
içinoperator ==
yöntemler. - Kayıt türleri uygular System.IEquatable<T>.
Kayıtlar ayrıca geçersiz Object.ToString()kılma sağlar. Derleyici, kullanarak Object.ToString()kayıtları görüntülemek için yöntemleri sentezler. Bu öğreticinin kodunu yazarken bu üyeleri keşfedeceksiniz. Kayıtların yıkıcı olmayan mutasyona neden olması için ifadeleri destekler with
.
Daha kısa bir söz dizimi kullanarak konumsal kayıtları da bildirebilirsiniz. Konumsal kayıtlar bildirdiğinizde derleyici sizin için daha fazla yöntem sentezler:
- Parametreleri kayıt bildirimindeki konumsal parametrelerle eşleşen bir birincil oluşturucu.
- Birincil oluşturucunun her parametresi için genel özellikler. Bu özellikler türler ve
readonly record struct
türler içinrecord class
yalnızca init'tir. Türler içinrecord struct
okuma-yazmadır. Deconstruct
Kayıttan özellikleri ayıklama yöntemi.
Sıcaklık verileri oluşturma
Veriler ve istatistikler, kayıtları kullanmak isteyeceğiniz senaryolar arasındadır. Bu öğreticide, farklı kullanımlar için derece günlerini hesaplayan bir uygulama oluşturacaksınız. Derece günleri , günler, haftalar veya aylar boyunca bir ısı ölçüsüdür (veya ısı eksikliği). Derece günleri enerji kullanımını izler ve tahmin edebilir. Daha sıcak günler daha fazla klima, daha soğuk günler ise daha fazla fırın kullanımı anlamına gelir. Derece günleri, bitki popülasyonlarının yönetilmesine yardımcı olur ve mevsimler değiştikçe bitki büyümesiyle bağıntı sağlar. Derece günleri, iklime uygun seyahat eden türler için hayvan göçlerinin izlenmesine yardımcı olur.
Formül, belirli bir gündeki ortalama sıcaklığı ve taban çizgisi sıcaklığını temel alır. Zaman içindeki derece günlerini hesaplamak için her gün belirli bir süre boyunca yüksek ve düşük sıcaklığa ihtiyacınız olacaktır. Yeni bir uygulama oluşturarak başlayalım. Yeni bir konsol uygulaması oluşturun. "DailyTemperature.cs" adlı yeni bir dosyada yeni bir kayıt türü oluşturun:
public readonly record struct DailyTemperature(double HighTemp, double LowTemp);
Yukarıdaki kod bir konumsal kayıt tanımlar. Kayıt DailyTemperature
bir readonly record struct
olur, çünkü bu kayıttan devralmayı amaçlamazsınız ve sabit olmalıdır. HighTemp
ve LowTemp
özellikleri yalnızca init özellikleridir, yani oluşturucuda veya özellik başlatıcı kullanılarak ayarlanabilir. Konumsal parametrelerin okuma-yazma olmasını istiyorsanız, yerine bir record struct
readonly record struct
bildirirsiniz. Türün DailyTemperature
ayrıca, iki özellikle eşleşen iki parametresi olan bir birincil oluşturucu vardır. Bir kaydı başlatmak DailyTemperature
için birincil oluşturucuyu kullanırsınız. Aşağıdaki kod birkaç DailyTemperature
kayıt oluşturur ve başlatır. İlki, ve LowTemp
'yi netleştirmek HighTemp
için adlandırılmış parametreleri kullanır. Kalan başlatıcılar ve LowTemp
'yi başlatmak HighTemp
için konumsal parametreleri kullanır:
private static DailyTemperature[] data = [
new DailyTemperature(HighTemp: 57, LowTemp: 30),
new DailyTemperature(60, 35),
new DailyTemperature(63, 33),
new DailyTemperature(68, 29),
new DailyTemperature(72, 47),
new DailyTemperature(75, 55),
new DailyTemperature(77, 55),
new DailyTemperature(72, 58),
new DailyTemperature(70, 47),
new DailyTemperature(77, 59),
new DailyTemperature(85, 65),
new DailyTemperature(87, 65),
new DailyTemperature(85, 72),
new DailyTemperature(83, 68),
new DailyTemperature(77, 65),
new DailyTemperature(72, 58),
new DailyTemperature(77, 55),
new DailyTemperature(76, 53),
new DailyTemperature(80, 60),
new DailyTemperature(85, 66)
];
Konumsal kayıtlar dahil olmak üzere kayıtlara kendi özelliklerinizi veya yöntemlerinizi ekleyebilirsiniz. Her gün için ortalama sıcaklığı hesaplamanız gerekir. Bu özelliği DailyTemperature
kayda ekleyebilirsiniz:
public readonly record struct DailyTemperature(double HighTemp, double LowTemp)
{
public double Mean => (HighTemp + LowTemp) / 2.0;
}
Şimdi bu verileri kullanabileceğinize emin olalım. Yönteminize Main
aşağıdaki kodu ekleyin:
foreach (var item in data)
Console.WriteLine(item);
Uygulamanızı çalıştırdığınızda aşağıdaki görüntüye benzer bir çıktı görürsünüz (alan için birkaç satır kaldırıldı):
DailyTemperature { HighTemp = 57, LowTemp = 30, Mean = 43.5 }
DailyTemperature { HighTemp = 60, LowTemp = 35, Mean = 47.5 }
DailyTemperature { HighTemp = 80, LowTemp = 60, Mean = 70 }
DailyTemperature { HighTemp = 85, LowTemp = 66, Mean = 75.5 }
Yukarıdaki kod, derleyici tarafından sentezlenen geçersiz kılma işleminin ToString
çıkışını gösterir. Farklı bir metin tercih ediyorsanız, derleyicinin ToString
sizin için bir sürümü sentezlemesini engelleyen kendi sürümünüzü yazabilirsiniz.
İşlem derecesi günleri
Derece günlerini hesaplamak için, belirli bir gündeki temel sıcaklık ile ortalama sıcaklık arasındaki farkı alırsınız. Zaman içindeki ısıyı ölçmek için, ortalama sıcaklığın taban çizgisinin altında olduğu günleri atarsınız. Zaman içindeki soğuk algınlıklarını ölçmek için, ortalama sıcaklığın taban çizgisinin üzerinde olduğu günleri atarsınız. Örneğin ABD, hem ısıtma hem de soğutma derecesi günlerinin tabanı olarak 65F kullanır. Bu, ısıtma veya soğutmanın gerekli olmadığı sıcaklıktır. Bir günün ortalama sıcaklığı 70F ise, o gün beş soğutma derece günü ve sıfır ısıtma derecesi günüdür. Buna karşılık, ortalama sıcaklık 55F ise, o gün 10 ısıtma derece günü ve 0 soğutma derecesi günüdür.
Bu formülleri küçük bir kayıt türleri hiyerarşisi olarak ifade edebilirsiniz: soyut bir derece gün türü ve ısıtma derecesi günleri ve soğutma derecesi günleri için iki somut tür. Bu türler konumsal kayıtlar da olabilir. Temel sıcaklığı ve günlük sıcaklık kayıtlarını birincil oluşturucuya bağımsız değişken olarak alır:
public abstract record DegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords);
public sealed record HeatingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
: DegreeDays(BaseTemperature, TempRecords)
{
public double DegreeDays => TempRecords.Where(s => s.Mean < BaseTemperature).Sum(s => BaseTemperature - s.Mean);
}
public sealed record CoolingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
: DegreeDays(BaseTemperature, TempRecords)
{
public double DegreeDays => TempRecords.Where(s => s.Mean > BaseTemperature).Sum(s => s.Mean - BaseTemperature);
}
Soyut DegreeDays
kayıt, hem hem CoolingDegreeDays
de HeatingDegreeDays
kayıtları için paylaşılan temel sınıftır. Türetilmiş kayıtlardaki birincil oluşturucu bildirimleri, temel kayıt başlatmanın nasıl yönetileceğini gösterir. Türetilmiş kaydınız, temel kayıt birincil oluşturucusunda tüm parametreler için parametreleri bildirir. Temel kayıt bu özellikleri bildirir ve başlatır. Türetilen kayıt bunları gizlemez, ancak yalnızca temel kaydında bildirilmeyen parametreler için özellikler oluşturur ve başlatır. Bu örnekte, türetilen kayıtlar yeni birincil oluşturucu parametreleri eklemez. Yönteminize aşağıdaki kodu ekleyerek kodunuzu test edin Main
:
var heatingDegreeDays = new HeatingDegreeDays(65, data);
Console.WriteLine(heatingDegreeDays);
var coolingDegreeDays = new CoolingDegreeDays(65, data);
Console.WriteLine(coolingDegreeDays);
Aşağıdaki ekran gibi bir çıkış alırsınız:
HeatingDegreeDays { BaseTemperature = 65, TempRecords = record_types.DailyTemperature[], DegreeDays = 85 }
CoolingDegreeDays { BaseTemperature = 65, TempRecords = record_types.DailyTemperature[], DegreeDays = 71.5 }
Derleyici tarafından sentezlenen yöntemleri tanımlama
Kodunuz, bu süre boyunca doğru ısıtma ve soğutma derecesi gün sayısını hesaplar. Ancak bu örnekte neden kayıtlar için sentezlenmiş yöntemlerden bazılarını değiştirmek isteyebileceğiniz gösterilmektedir. Kopyalama yöntemi dışında bir kayıt türünde derleyici tarafından sentezlenen yöntemlerden herhangi birinin kendi sürümünü bildirebilirsiniz. Kopyalama yönteminin derleyici tarafından oluşturulan bir adı vardır ve farklı bir uygulama sağlayamazsınız. Bu sentezlenmiş yöntemler arasında bir kopya oluşturucu, arabirimin System.IEquatable<T> üyeleri, eşitlik ve eşitsizlik testleri ve GetHashCode()bulunur. Bu amaçla sentezleyeceksiniz PrintMembers
. Kendi öğesini ToString
de bildirebilirsiniz, ancak PrintMembers
devralma senaryoları için daha iyi bir seçenek sağlar. Sentezlenmiş yöntemin kendi sürümünü sağlamak için imzanın sentezlenen yöntemle eşleşmesi gerekir.
TempRecords
Konsol çıkışındaki öğesi kullanışlı değildir. Türü görüntüler, ancak başka bir şey görüntülemez. Sentezlenen PrintMembers
yöntemin kendi uygulamasını sağlayarak bu davranışı değiştirebilirsiniz. İmza, bildirime uygulanan değiştiricilere record
bağlıdır:
- Bir kayıt türü
sealed
veyarecord struct
ise, imzadırprivate bool PrintMembers(StringBuilder builder);
- Bir kayıt türü değilse
sealed
ve türündenobject
türetilirse (yani, temel kayıt bildirmezse), imza şu şekildedir:protected virtual bool PrintMembers(StringBuilder builder);
- Kayıt türü değilse
sealed
ve başka bir kayıttan türetiliyorsa, imza şu şekildedir:protected override bool PrintMembers(StringBuilder builder);
Bu kuralların amacını anlayarak anlaşılması en kolay yolu budur PrintMembers
. PrintMembers
bir dizeye kayıt türündeki her özellik hakkında bilgi ekler. Sözleşme, üyelerini görüntülemeye eklemek için temel kayıtları gerektirir ve türetilmiş üyelerin üyelerini ekleyeceğini varsayar. Her kayıt türü için aşağıdaki örneğe HeatingDegreeDays
benzer bir ToString
geçersiz kılma sentezler:
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("HeatingDegreeDays");
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(" ");
}
stringBuilder.Append("}");
return stringBuilder.ToString();
}
Kayıtta koleksiyonun DegreeDays
türünü yazdırmayan bir PrintMembers
yöntem bildirirsiniz:
protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
stringBuilder.Append($"BaseTemperature = {BaseTemperature}");
return true;
}
İmza, derleyicinin sürümüyle eşleşmesi için bir virtual protected
yöntem bildirir. Aksesuarı yanlış alırsanız endişelenmeyin; dil, doğru imzayı zorlar. Sentezlenen herhangi bir yöntem için doğru değiştiricileri unutursanız, derleyici doğru imzayı almanıza yardımcı olacak uyarılar veya hatalar oluşturur.
C# 10 ve sonraki sürümlerde, yöntemini bir kayıt türünde olduğu gibi sealed
bildirebilirsinizToString
. Bu, türetilmiş kayıtların yeni bir uygulama sağlamasını engeller. Türetilmiş kayıtlar yine de geçersiz kılmayı PrintMembers
içerir. Kaydın çalışma zamanı türünü görüntülemesini istemiyorsanız mühürleyebilirsiniz ToString
. Yukarıdaki örnekte, kaydın ısıtma veya soğutma derecesi günlerini nerede ölçtdüğüne ilişkin bilgileri kaybedersiniz.
Yıkıcı olmayan mutasyon
Konumsal kayıt sınıfındaki sentezlenmiş üyeler kaydın durumunu değiştirmez. Amaç, sabit kayıtları daha kolay oluşturabilmenizdir. Sabit bir kayıt yapısı oluşturmak için bir bildirdiğiniz readonly record struct
unutmayın. ve CoolingDegreeDays
için HeatingDegreeDays
önceki bildirimlere yeniden bakın. Eklenen üyeler, kaydın değerleri üzerinde hesaplamalar gerçekleştirir, ancak durumu sessize almaz. Konumsal kayıtlar sabit başvuru türleri oluşturmanızı kolaylaştırır.
Sabit başvuru türleri oluşturmak, yıkıcı olmayan mutasyon kullanmak isteyeceğiniz anlamına gelir. İfadeleri kullanarak with
mevcut kayıt örneklerine benzer yeni kayıt örnekleri oluşturursunuz. Bu ifadeler, kopyayı değiştiren ek atamaları olan bir kopya yapısıdır. Sonuç, her özelliğin mevcut kayıttan kopyalandığı ve isteğe bağlı olarak değiştirildiği yeni bir kayıt örneğidir. Özgün kayıt değiştirilmez.
Şimdi programınıza ifadeleri gösteren with
birkaç özellik ekleyelim. İlk olarak, aynı verileri kullanarak artan dereceli günleri hesaplamak için yeni bir kayıt oluşturalım. Artan derece günleri genellikle taban çizgisi olarak 41F kullanır ve sıcaklıkları taban çizgisinin üzerinde ölçer. Aynı verileri kullanmak için, öğesine benzer coolingDegreeDays
ancak farklı bir temel sıcaklığa sahip yeni bir kayıt oluşturabilirsiniz:
// Growing degree days measure warming to determine plant growing rates
var growingDegreeDays = coolingDegreeDays with { BaseTemperature = 41 };
Console.WriteLine(growingDegreeDays);
Hesaplanan derece sayısını, daha yüksek bir taban çizgisi sıcaklığıyla oluşturulan sayılarla karşılaştırabilirsiniz. Kayıtların başvuru türleri ve bu kopyaların basit kopyalar olduğunu unutmayın. Verilerin dizisi kopyalanır, ancak her iki kayıt da aynı verilere başvurur. Bu gerçek, başka bir senaryoda bir avantajdır. Artan derece gün sayısı için, önceki beş günün toplamını izlemek yararlı olur. İfadeleri kullanarak with
farklı kaynak verilerle yeni kayıtlar oluşturabilirsiniz. Aşağıdaki kod bu birikimlerden oluşan bir koleksiyon oluşturur ve değerleri görüntüler:
// showing moving accumulation of 5 days using range syntax
List<CoolingDegreeDays> movingAccumulation = new();
int rangeSize = (data.Length > 5) ? 5 : data.Length;
for (int start = 0; start < data.Length - rangeSize; start++)
{
var fiveDayTotal = growingDegreeDays with { TempRecords = data[start..(start + rangeSize)] };
movingAccumulation.Add(fiveDayTotal);
}
Console.WriteLine();
Console.WriteLine("Total degree days in the last five days");
foreach(var item in movingAccumulation)
{
Console.WriteLine(item);
}
Kayıtların kopyalarını oluşturmak için ifadeleri de kullanabilirsiniz with
. İfadenin ayraçları with
arasında hiçbir özellik belirtmeyin. Başka bir deyişle, bir kopya oluşturun ve hiçbir özelliği değiştirmeyin:
var growingDegreeDaysCopy = growingDegreeDays with { };
Sonuçları görmek için tamamlanmış uygulamayı çalıştırın.
Özet
Bu öğreticide kayıtların çeşitli yönleri gösterildi. Kayıtlar, temel kullanımın verileri depoladığı türler için kısa söz dizimi sağlar. Nesne odaklı sınıflar için temel kullanım sorumlulukları tanımlamaktır. Bu öğretici, bir kaydın özelliklerini bildirmek için kısa bir söz dizimi kullanabileceğiniz konumsal kayıtlara odaklanmıştır. Derleyici, kayıtları kopyalamak ve karşılaştırmak için kaydın birkaç üyesini sentezler. Kayıt türleriniz için ihtiyacınız olan diğer üyeleri ekleyebilirsiniz. Derleyici tarafından oluşturulan üyelerin hiçbirinin durumu sessize almayacağını bilerek sabit kayıt türleri oluşturabilirsiniz. İfadeler with
yıkıcı olmayan mutasyonu desteklemeyi kolaylaştırır.
Kayıtlar türleri tanımlamak için başka bir yol ekler. Tanımları, nesnelerin sorumluluklarına ve davranışlarına odaklanan nesne odaklı hiyerarşiler oluşturmak için kullanırsınız class
. Verileri depolayan ve verimli bir şekilde kopyalamak için yeterince küçük olan veri yapıları için türler oluşturursunuz struct
. Değer tabanlı eşitlik ve karşılaştırma istediğinizde, değerleri kopyalamak istemediğinizde ve başvuru değişkenlerini kullanmak istediğinizde türler oluşturursunuz record
. Verimli bir şekilde kopyalanacak kadar küçük bir tür için kayıtların özelliklerini istediğinizde türler oluşturursunuz record struct
.
Kayıt türü ve önerilen kayıt türü belirtimi ve kayıt yapısı belirtimiiçin C# dil başvurusu makalesinde kayıtlar hakkında daha fazla bilgi edinebilirsiniz.