Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Not
Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.
Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar, dil tasarım toplantısına (LDM) aitilgili notlarda kaydedilir.
Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek için
Şampiyon sorunu: https://github.com/dotnet/csharplang/issues/39
Bu teklif, C# dil tasarım ekibi tarafından kabul edilen C# 9 kayıtları özelliğinin belirtimini izler.
Kaydın söz dizimi aşağıdaki gibidir:
record_declaration
: attributes? class_modifier* 'partial'? 'record' identifier type_parameter_list?
parameter_list? record_base? type_parameter_constraints_clause* record_body
;
record_base
: ':' class_type argument_list?
| ':' interface_type_list
| ':' class_type argument_list? ',' interface_type_list
;
record_body
: '{' class_member_declaration* '}' ';'?
| ';'
;
Kayıt türleri, bir sınıf bildirimine benzer başvuru türleridir.
record_base
bir argument_list
içermiyorsa, kaydın record_declaration
parameter_list
sağlaması bir hatadır.
Kısmi kaydın en fazla bir kısmi tür bildirimi parameter_list
sağlayabilir.
Kayıt parametreleri ref
, out
veya this
değiştiricileri kullanamaz (ancak in
ve params
izin verilir).
Miras
Kayıtlar, sınıf object
olmadığı sürece sınıflardan devralamaz ve sınıflar kayıtlardan devralamaz. Kayıtlar diğer kayıtlardan devralabilir.
Kayıt türünün üyeleri
Kayıt gövdesinde bildirilen üyelere ek olarak, bir kayıt türü ek sentezlenmiş üyelere sahiptir. Kayıt gövdesinde "eşleşen" imzaya sahip bir üye bildirilmediği veya "eşleşen" imzaya sahip erişilebilir somut sanal olmayan bir üye devralınmadığı sürece üyeler sentezlenir. Eşleşen üye, derleyicinin başka hiçbir sentezlenmiş üyeyi değil bu üyeyi oluşturmasını engeller. İki üye, aynı imzaya sahipse veya devralma senaryosunda "gizlendiği" kabul edilirse eşleşen olarak kabul edilir. Bir kaydın üyesinin "Clone" olarak adlandırılması hatadır. Bir kaydın örnek alanının en üst düzey işaretçi türüne sahip olması hatadır. bir işaretçi dizisi gibi iç içe işaretçi türüne izin verilir.
Sentezlenen üyeler aşağıdaki gibidir:
Eşitlik üyeleri
Eğer kayıt object
'dan türetilmişse, kayıt türü, aşağıdaki gibi özellik olarak bildirilen bir özelliğe eşdeğer sentezlenmiş bir salt okunur özelliği içerir.
Type EqualityContract { get; }
Kayıt türü private
ise özelliği sealed
. Aksi takdirde özelliği virtual
ve protected
.
özelliği açıkça bildirilebilir. Açık bildirim beklenen imza veya erişilebilirlikle eşleşmiyorsa veya açık bildirimin türetilmiş bir türde geçersiz kılınmasına izin vermemesi ve kayıt türünün sealed
olmaması bir hatadır.
Kayıt türü Base
bir temel kayıt türünden türetilmişse, kayıt türü aşağıdaki gibi bildirilen bir özelliğe eşdeğer bir sentezlenmiş salt okunur özellik içerir:
protected override Type EqualityContract { get; }
özelliği açıkça bildirilebilir. Açık bildirim beklenen imza veya erişilebilirlikle eşleşmiyorsa veya açık bildirimin türetilmiş bir türde geçersiz kılınmasına izin vermemesi ve kayıt türünün sealed
olmaması bir hatadır. Sentezlenmiş veya açıkça bildirilen herhangi bir özellik, kayıt türü Base
'da bu imzaya sahip bir özelliği geçersiz kılmazsa (örneğin, özellik Base
'de eksikse, mühürlü veya sanal değilse), bu bir hatadır.
Sentezlenen özellik, typeof(R)
kayıt türü olduğunda R
döndürür.
Kayıt türü System.IEquatable<R>
'ı uygular ve Equals(R? other)
'nin kayıt türü olduğu durumda sentezlenmiş, güçlü türde bir aşırı yük içeren R
'i içerir.
Yöntem, public
'dir ve kayıt türü virtual
olmadığı sürece yöntem sealed
'dir.
yöntemi açıkça bildirilebilir. Açık bildirim beklenen imza veya erişilebilirlikle eşleşmiyorsa veya açık bildirim türetilmiş bir türde geçersiz kılınmasına izin vermiyorsa ve kayıt türü sealed
değilse hatadır.
Equals(R? other)
kullanıcı tanımlıysa (sentezlenmediyse) ancak GetHashCode
değilse, bir uyarı oluşturulur.
public virtual bool Equals(R? other);
Sentezlenen Equals(R?)
, yalnızca aşağıdakilerden her biri true
ise true
döndürür:
-
other
,null
değildir ve - Devralınmayan kayıt türünde her
fieldN
örnek alanı için,System.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)
alan türü olanTN
değeri ve - Temel kayıt türü varsa,
base.Equals(other)
değeri (public virtual bool Equals(Base? other)
'e yapılan sanal olmayan bir çağrı); aksi takdirdeEqualityContract == other.EqualityContract
değeri.
Kayıt türü, aşağıdaki gibi bildirilen işleçlere eşdeğer sentezlenmiş ==
ve !=
işleçleri içerir:
public static bool operator==(R? left, R? right)
=> (object)left == right || (left?.Equals(right) ?? false);
public static bool operator!=(R? left, R? right)
=> !(left == right);
Equals
işleci tarafından çağrılan ==
yöntemi, yukarıda belirtilen Equals(R? other)
yöntemidir.
!=
işleci, ==
işlemcisine yetki verir. İşleçler açıkça bildirilirse bu bir hatadır.
Kayıt türü Base
bir temel kayıt türünden türetilmişse, kayıt türü aşağıdaki gibi bildirilen bir yönteme eşdeğer olan sentetik bir geçersiz kılma içerir:
public sealed override bool Equals(Base? other);
Geçersiz kılma açıkça bildirilirse bu bir hatadır. Yöntem Base
kayıt türünde aynı imzaya sahip bir yöntemi geçersiz kılmazsa (örneğin, yöntem Base
eksikse veya korumalıysa veya sanal değilse) bir hatadır.
Sentezlenen geçersiz kılma, Equals((object?)other)
'ı döndürür.
Kayıt türü, aşağıdaki gibi bildirilen bir yönteme eşdeğer bir sentezlenmiş geçersiz kılma içerir:
public override bool Equals(object? obj);
Geçersiz kılma açıkça bildirilirse bu bir hatadır. Yöntem object.Equals(object? obj)
geçersiz kılmazsa (örneğin, ara taban türlerinde gölgeleme nedeniyle vb.) bir hatadır.
Sentezlenen geçersiz kılma, Equals(other as R)
'in kayıt türü olduğu durumda R
döndürür.
Kayıt türü, aşağıdaki gibi bildirilen bir yönteme eşdeğer bir sentezlenmiş geçersiz kılma içerir:
public override int GetHashCode();
yöntemi açıkça bildirilebilir.
Açık bildirimin türetilmiş bir türde geçersiz kılınmasına izin vermemesi ve kayıt türünün sealed
olmaması bir hatadır. Sentezlenmiş veya açıkça tanımlanmış bir metot, object.GetHashCode()
'ı geçersiz kılmazsa (örneğin, ara taban türlerinde gölgeleme nedeniyle) bu bir hatadır.
Equals(R?)
ve GetHashCode()
'den biri açıkça bildirilirse, ancak diğer yöntem açıkça bildirilmemişse bir uyarı bildirilir.
GetHashCode()
sentezlenmiş değiştirme, aşağıdaki değerlerin birleşiminin int
sonucunu döndürür:
- Devralınmayan kayıt türünde her
fieldN
örnek alanı için,System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)
alan türü olanTN
değeri ve - Bir temel kayıt türü varsa,
base.GetHashCode()
değeri; aksi takdirdeSystem.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract)
değeri.
Örneğin, aşağıdaki kayıt türlerini göz önünde bulundurun:
record R1(T1 P1);
record R2(T1 P1, T2 P2) : R1(P1);
record R3(T1 P1, T2 P2, T3 P3) : R2(P1, P2);
Bu kayıt türleri için, sentezlenen eşitlik üyeleri şöyle olacaktır:
class R1 : IEquatable<R1>
{
public T1 P1 { get; init; }
protected virtual Type EqualityContract => typeof(R1);
public override bool Equals(object? obj) => Equals(obj as R1);
public virtual bool Equals(R1? other)
{
return !(other is null) &&
EqualityContract == other.EqualityContract &&
EqualityComparer<T1>.Default.Equals(P1, other.P1);
}
public static bool operator==(R1? left, R1? right)
=> (object)left == right || (left?.Equals(right) ?? false);
public static bool operator!=(R1? left, R1? right)
=> !(left == right);
public override int GetHashCode()
{
return HashCode.Combine(EqualityComparer<Type>.Default.GetHashCode(EqualityContract),
EqualityComparer<T1>.Default.GetHashCode(P1));
}
}
class R2 : R1, IEquatable<R2>
{
public T2 P2 { get; init; }
protected override Type EqualityContract => typeof(R2);
public override bool Equals(object? obj) => Equals(obj as R2);
public sealed override bool Equals(R1? other) => Equals((object?)other);
public virtual bool Equals(R2? other)
{
return base.Equals((R1?)other) &&
EqualityComparer<T2>.Default.Equals(P2, other.P2);
}
public static bool operator==(R2? left, R2? right)
=> (object)left == right || (left?.Equals(right) ?? false);
public static bool operator!=(R2? left, R2? right)
=> !(left == right);
public override int GetHashCode()
{
return HashCode.Combine(base.GetHashCode(),
EqualityComparer<T2>.Default.GetHashCode(P2));
}
}
class R3 : R2, IEquatable<R3>
{
public T3 P3 { get; init; }
protected override Type EqualityContract => typeof(R3);
public override bool Equals(object? obj) => Equals(obj as R3);
public sealed override bool Equals(R2? other) => Equals((object?)other);
public virtual bool Equals(R3? other)
{
return base.Equals((R2?)other) &&
EqualityComparer<T3>.Default.Equals(P3, other.P3);
}
public static bool operator==(R3? left, R3? right)
=> (object)left == right || (left?.Equals(right) ?? false);
public static bool operator!=(R3? left, R3? right)
=> !(left == right);
public override int GetHashCode()
{
return HashCode.Combine(base.GetHashCode(),
EqualityComparer<T3>.Default.GetHashCode(P3));
}
}
Üyeleri kopyala ve çoğalt
Kayıt türü iki kopyalanabilir eleman içerir.
- Kayıt türünden tek bir parametre alan oluşturucu. "Kopya oluşturucu" olarak adlandırılır.
- Derleyici tarafından ayrılmış bir ada sahip sentezlenmiş genel parametresiz örnek "clone" yöntemi
Kopyalama oluşturucusunun amacı, durumu parametresinden oluşturulan yeni örneğe kopyalamaktır. Bu oluşturucu, kayıt bildiriminde bulunan örnek alanı/özellik başlatıcılarını çalıştırmaz. Oluşturucu açıkça bildirilmemişse, derleyici tarafından bir oluşturucu sentezlenir. Kayıt mühürlüyse, oluşturucu özel olacak, aksi takdirde korumalı olacaktır. Açıkça bildirilen bir kopya oluşturucu, kayıt mühürlenmediği sürece genel veya korumalı olmalıdır. Oluşturucunun yapması gereken ilk şey, temel kopya oluşturucuyu veya kayıt nesneden devralıyorsa parametresiz nesne oluşturucuyu çağırmaktır. Kullanıcı tanımlı bir kopya oluşturucu bu gereksinimi karşılamayan örtük veya açık bir oluşturucu başlatıcı kullanıyorsa bir hata bildirilir. Bir temel kopya oluşturucu çağrıldıktan sonra, sentezlenmiş kopya oluşturucu kayıt türü içinde örtük veya açıkça bildirilen tüm örnek alanları için değerleri kopyalar. İster açık ister örtük olsun, bir kopya oluşturucunun tek varlığı, varsayılan örnek oluşturucunun otomatik olarak eklenmesini engellemez.
Temel kayıtta sanal bir "clone" yöntemi varsa, sentezlenen "clone" yöntemi bunu geçersiz kılar ve yöntemin dönüş türü şu anda içinde bulunan türdür. Temel kayıt klonlama metodu mühürlüyse bir hata oluşturulur. Temel kayıtta sanal bir "clone" yöntemi yoksa, kayıt korumalı veya soyut olmadığı sürece kopyalama yönteminin dönüş türü içeren türdür ve yöntem sanaldır. İçeren kayıt soyutsa, sentezlenen kopya yöntemi de soyut olur. "clone" yöntemi soyut değilse, bir kopyalama oluşturucusunun çağrısının sonucunu döndürür.
Üyelerin yazdırılması: PrintMembers ve ToString yöntemleri
Kayıt object
türetilmişse, kayıt aşağıdaki gibi bildirilen bir yönteme eşdeğer bir sentezlenmiş yöntem içerir:
bool PrintMembers(System.Text.StringBuilder builder);
Kayıt türü private
ise yöntemi sealed
. Aksi takdirde yöntem virtual
ve protected
'dir.
Yöntemi:
- yöntemi varsa ve kayıt yazdırılabilir üyelere sahipse
System.Runtime.CompilerServices.RuntimeHelpers.EnsureSufficientExecutionStack()
yöntemini çağırır. - kaydın yazdırılabilir üyelerinin her biri için (statik olmayan ortak alan ve okunabilir özellik üyeleri), bu üyenin adını ve ardından " = " ekler ve ardından üyenin değeri ", ", " ile ayrılır
- kaydın yazdırılabilir üyeleri varsa true değerini döndürür.
Değer türüne sahip bir üye için, hedef platformda kullanılabilen en verimli yöntemi kullanarak değerini dize gösterimine dönüştüreceğiz. Şu anda bu, ToString
'e geçmeden önce StringBuilder.Append
'ı çağırmak anlamına gelir.
Kayıt türü Base
bir temel kayıttan türetilmişse, kayıt aşağıdaki gibi bildirilen bir yönteme eşdeğer bir sentezlenmiş geçersiz kılma içerir:
protected override bool PrintMembers(StringBuilder builder);
Eğer kaydın yazdırılabilir üyesi yoksa, temel PrintMembers
yöntemini builder
parametresi ile çağırır ve sonucu döndürür.
Aksi takdirde yöntem:
- bir bağımsız değişkenle (
PrintMembers
parametresi) temelbuilder
yöntemini çağırır. -
PrintMembers
yöntemi true döndürdüyse, oluşturucuya ", " ekleyin, - kaydın yazdırılabilir üyelerinin her biri için, önce üyenin adını, ardından " = " ve ardından üyenin değerini ekler:
this.member
(veya değer türleri içinthis.member.ToString()
), ", " ile ayrılarak. - true değerini döndürür.
PrintMembers
yöntemi açıkça bildirilebilir.
Açık bildirim beklenen imza veya erişilebilirlikle eşleşmiyorsa veya açık bildirimin türetilmiş bir türde geçersiz kılınmasına izin vermemesi ve kayıt türünün sealed
olmaması bir hatadır.
Kayıt, aşağıdaki gibi bildirilen bir yönteme eşdeğer bir sentezlenmiş yöntem içerir:
public override string ToString();
yöntemi açıkça bildirilebilir. Açık bildirim beklenen imza veya erişilebilirlikle eşleşmiyorsa veya açık bildirimin türetilmiş bir türde geçersiz kılınmasına izin vermemesi ve kayıt türünün sealed
olmaması bir hatadır. Sentezlenmiş veya açıkça tanımlanmış bir metot, object.ToString()
'ı geçersiz kılmazsa (örneğin, ara taban türlerinde gölgeleme nedeniyle) bu bir hatadır.
Sentezlenen yöntem:
- bir
StringBuilder
örneği oluşturur, - kayıt adını oluşturucuya ekler, ardından " { "
- kaydın
PrintMembers
yöntemini, ona oluşturucuyu vererek çağırır ve eğer true döndürdüyse, ardından " " ekler. - ekler "}",
-
builder.ToString()
ile yapıcının içeriğini döndürür.
Örneğin, aşağıdaki kayıt türlerini göz önünde bulundurun:
record R1(T1 P1);
record R2(T1 P1, T2 P2, T3 P3) : R1(P1);
Bu kayıt türleri için sentezlenmiş yazdırma üyeleri şöyle olabilir:
class R1 : IEquatable<R1>
{
public T1 P1 { get; init; }
protected virtual bool PrintMembers(StringBuilder builder)
{
builder.Append(nameof(P1));
builder.Append(" = ");
builder.Append(this.P1); // or builder.Append(this.P1.ToString()); if T1 is a value type
return true;
}
public override string ToString()
{
var builder = new StringBuilder();
builder.Append(nameof(R1));
builder.Append(" { ");
if (PrintMembers(builder))
builder.Append(" ");
builder.Append("}");
return builder.ToString();
}
}
class R2 : R1, IEquatable<R2>
{
public T2 P2 { get; init; }
public T3 P3 { get; init; }
protected override bool PrintMembers(StringBuilder builder)
{
if (base.PrintMembers(builder))
builder.Append(", ");
builder.Append(nameof(P2));
builder.Append(" = ");
builder.Append(this.P2); // or builder.Append(this.P2); if T2 is a value type
builder.Append(", ");
builder.Append(nameof(P3));
builder.Append(" = ");
builder.Append(this.P3); // or builder.Append(this.P3); if T3 is a value type
return true;
}
public override string ToString()
{
var builder = new StringBuilder();
builder.Append(nameof(R2));
builder.Append(" { ");
if (PrintMembers(builder))
builder.Append(" ");
builder.Append("}");
return builder.ToString();
}
}
Konumsal kayıt üyeleri
Yukarıdaki üyelere ek olarak, parametre listesi ("konumsal kayıtlar") içeren kayıtlar, yukarıdaki üyelerle aynı koşullara sahip ek üyeleri sentezler.
Birincil Oluşturucu
Tür bildiriminin değer parametrelerine karşılık gelen imzaya sahip bir genel oluşturucuya sahip bir kayıt türü vardır. Tür için birincil oluşturucu olarak adlandırılır ve varsa örtük olarak bildirilen varsayılan sınıf oluşturucunun bastırılmasına neden olur. Birincil oluşturucunun ve aynı imzaya sahip bir oluşturucunun sınıfta zaten mevcut olması bir hatadır.
Çalışma zamanında birincil oluşturucu
sınıf gövdesinde görünen örnek başlatıcılarını yürütür
varsa,
record_base
yan tümcesinde sağlanan bağımsız değişkenlerle temel sınıf oluşturucuyu çağırır
Bir kaydın birincil oluşturucusu varsa, "kopya oluşturucu" dışında kullanıcı tanımlı oluşturucuların açık bir this
oluşturucu başlatıcısına sahip olması gerekir.
Birincil oluşturucunun ve kaydın üyelerinin parametreleri, argument_list
yan tümcesinin record_base
kapsamında ve örnek alanlarının veya özelliklerinin başlatıcıları içinde yer alır. Örnek üyeleri bu konumlarda bir hata olabilir (örnek üyelerinin bugün normal oluşturucu başlatıcılarında kapsamda yer almalarına benzer, ancak kullanılması gereken bir hatadır), ancak birincil oluşturucunun parametreleri kapsam içinde ve kullanılabilir olur ve üyeleri gölgeler. Statik üyeler, temel çağrıların ve başlatıcıların günümüzde normal oluşturucularda çalışma şekline benzer şekilde de kullanılabilir.
Birincil oluşturucunun parametresi okunmazsa bir uyarı oluşturulur.
argument_list
’da bildirilen ifade değişkenleri, argument_list
kapsamı içindedir. Normal bir oluşturucu başlatıcısının bağımsız değişken listesinde olduğu gibi, aynı gölgeleme kuralları uygulanır.
Özellikler
Kayıt türü bildiriminin her bir kayıt parametresi için, adı ve türü değer parametresi bildiriminden alınan karşılık gelen bir genel özellik üyesi vardır.
Kayıt amaçlı:
- Genel
get
veinit
otomatik özelliği oluşturulur (bkz. ayrıinit
erişimci belirtimi). Eşleşen türe sahip devralınanabstract
özelliği geçersiz kılınır. Devralınan özelliğin geçersiz kılınabilir erişimcileripublic
,get
veinit
yoksa bu bir hatadır. Devralınan özellik gizliyse bu bir hatadır.
Otomatik özellik, karşılık gelen birincil oluşturucu parametresinin değerine ilk değer atanır. Öznitelikler, ilgili kayıt parametresine sözdizimsel olarak uygulanan öznitelikler içinproperty:
veyafield:
hedefleri kullanılarak, oluşturulmuş otomatik özelliğe ve onun destekleyici alanına uygulanabilir.
Parçalarına ayır
En az bir parametreye sahip konumsal kayıt, birincil oluşturucu bildiriminin her parametresi için out parametre bildirimi ile Deconstruct adlı genel bir void-dönüş örneği yöntemini sentezler.
Deconstruct
yönteminin her parametresi, birincil oluşturucu bildiriminin karşılık gelen parametresiyle aynı türe sahiptir. Yönteminin gövdesi, Deconstruct
yönteminin her parametresine, aynı ada sahip olan örnek özelliğinin değerini atar.
yöntemi açıkça bildirilebilir. Açık bildirimin beklenen imza veya erişilebilirlikle eşleşmemesi veya statik olması bir hatadır.
Aşağıdaki örnek, derleyici tarafından sentezlenmiş R
yöntemiyle ve kullanımıyla birlikte Deconstruct
konumsal kaydı göstermektedir:
public record R(int P1, string P2 = "xyz")
{
public void Deconstruct(out int P1, out string P2)
{
P1 = this.P1;
P2 = this.P2;
}
}
class Program
{
static void Main()
{
R r = new R(12);
(int p1, string p2) = r;
Console.WriteLine($"p1: {p1}, p2: {p2}");
}
}
with
ifadesi
with
ifadesi, aşağıdaki söz dizimini kullanan yeni bir ifadedir.
with_expression
: switch_expression
| switch_expression 'with' '{' member_initializer_list? '}'
;
member_initializer_list
: member_initializer (',' member_initializer)*
;
member_initializer
: identifier '=' expression
;
with
ifadesinin bir deyim olarak kullanılmasına izin verilmez.
with
ifadesi, member_initializer_list
atamalarında yapılan değişikliklerle alıcı ifadesinin bir kopyasını üretmek için tasarlanan "yıkıcı olmayan mutasyona" olanak tanır.
with
ifadesinin geçerli sayılması için alıcısının void olmayan bir türe sahip olması gerekir. Alıcı türü bir kayıt olmalıdır.
İlk olarak, alıcının "clone" yöntemi (yukarıda belirtilen) çağrılır ve sonucu alıcının türüne dönüştürülür. Ardından her member_initializer
, dönüştürme sonucunun bir alana veya özellik erişimine yapılan atamayla aynı şekilde işlenir. Atamalar alfabetik sırayla işlenir.
C# feature specifications