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.
Şampiyonluk sorunu: https://github.com/dotnet/csharplang/issues/9499
Summary
Bir sınıfın bildirilmesine closedizin verin. Bu, doğrudan türetilmiş sınıfların farklı bir derlemede bildirılmasını engeller:
// Assembly 1
public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;
// Assembly 2
public record class Locked : GateState; // ERROR - 'GateState' is a closed class
Tüm türetilmiş sınıflar kapalı sınıfın derlemesinde bildirildiğinden, hepsini kapsayan bir tüketim switch ifadesi kapalı sınıfı "tüketir" sonucuna varılabilir; uyarılardan kaçınmak için varsayılan bir durum sağlaması gerekmez.
// Assembly 3
GateState state = ...;
string description = state switch
{
Closed => "closed",
Open(var percent) => $"{percent}% open"
// No warning about missing cases
};
Motivasyon
Birçok sınıf türü, yazarları dışında herkes tarafından genişletilmeye yönelik değildir, ancak dil bu amacı ifade etmek için hiçbir yol sağlamaz, bunun olmasına karşı koruma sağlar. Sınıfın tüketicileri için bu, türetilmiş sınıfların hiçbir kümesinin temel sınıfı "tüketeceği" kabul edileceği ve bir anahtar ifadesinin uyarılardan kaçınmak için tümünü yakala büyük/küçük harf içermesi gerektiği anlamına gelir.
Kapalı sınıflar, türetilmiş bir sınıf kümesinin tamamlandığını göstermek için bir yol sağlar ve anahtar ifadelerinde kapsamlı olması için kodun buna güvenmesine izin verir.
Ayrıntılı tasarım
Sözdizimi
Sınıflarda değiştirici olarak izin ver closed . Sınıf closed örtük olarak soyuttur. Bu nedenle, bir veya static değiştiricisi de sealed olamaz.
Bir sınıf üzerinde değiştiriciyi açıkça kullanmak abstract bir closed hatadır.
Kapalı bir sınıftan türetilen bir sınıf açıkça bildirilmediği sürece kendisi kapatılmaz .
Aynı derleme kısıtlaması
Bir derlemedeki bir sınıf bildirilirse closed , doğrudan başka bir derlemede ondan türetilen bir hatadır:
// Assembly 1
public closed class CC { ... }
public class CO : CC { ... } // Ok, same assembly
// Assembly 2
public class C1 : CC { ... } // Error, 'CC' is closed and in a different assembly
public class C2 : CO { ... } // Ok, 'CO' is not closed
Aynı kısıtlama modüller için de geçerlidir. Bir türün closed alt türü, temel türle aynı modülde bulunmalıdır.
Tür parametresi kısıtlaması
Genel bir sınıf doğrudan kapalı bir sınıftan türetilirse, tüm tür parametreleri temel sınıf belirtiminde kullanılmalıdır:
closed class C<T> { ... }
class D1<U> : C<U> { ... } // Ok, 'U' is used in base class
class D2<V> : C<V[]> { ... } // Ok, 'V' is used in base class
class D3<W> : C<int> { ... } // Error, 'W' is not used in base class
Bu kural, türetilmiş türün kapalı temel türün belirli bir genel örneğini "tüketen" tek bir genel örnekleme olduğundan emin olmaktır.
Not: Bir noktada kapalı arabirimlere izin verirsek bu kural yeterli olmayabilir, çünkü a) sınıflar aynı arabirimin birden çok genel örneğini uygulayabilir ve b) arabirim türü parametreleri ortak veya değişken karşıtı olabilir. Bu noktada, kapalı bir temel türün genel örneklemesi başına belirli bir türetilmiş türün tek bir genel örneği olduğundan emin olmak için kuralı iyileştirmemiz gerekir.
Anahtarlarda tükenmişlik
switch Kapalı bir sınıfın doğrudan alt bileşenlerinin tümünü işleyen bir ifadenin bu sınıfı tüketmiş olduğu kabul edilir. Bu, bazı tükenmezlik uyarılarının artık verilmeyeceği anlamına gelir:
CC cc = ...;
_ = cc switch
{
CO co => ...,
// No warning about non-exhaustive switch
};
Öte yandan bu, kapalı temel sınıfın tüm doğrudan alt öğelerinden sonra bir durum olarak gerçekleşmesinin bir hata olabileceği anlamına da gelir:
_ = cc switch
{
CO co => ...,
CC cc => ..., // Error, case cannot be reached
};
Not: Kapalı bir temel sınıfın belirli genel örneklemeleri için geçerli türetilmiş sınıflar olmayabilir. Kapsamlı bir anahtarın yalnızca gerçekten mümkün olan türetilmiş türler için durumları belirtmesi gerekir.
Örneğin:
closed class C<T> { ... }
class D1<U> : C<U> { ... }
class D2<V> : C<V[]> { ... }
C<string>Örneğin, için karşılık gelen örneği D2<...>yoktur ve anahtarda herhangi bir örnek D2<...> verilmesi gerekmez:
C<string> cs = ...;
_ = cs switch
{
D1<string> d1 => ...,
// No need for a 'D2<...>' case - no instantiation corresponds to 'C<string>'
}
Alt tür kullanılamadığında kapsamlılık
Kısıtlama ihlalleri, erişilebilirlik ihlalleri veya başka nedenlerle belirli bir kullanım sitesinde bir alt tür geçerli değilse, anahtarı alt türlerle tüketmek mümkün değildir.
closed class C;
class D1 : C;
class Container
{
protected class D2 : C;
}
class Program
{
int M(C c)
=> c switch
{
D1 => 1,
// warning: switch is non-exhaustive. Pattern 'C' is not handled.
};
}
Bu durum, genel bir alt türün söylenebilir olmaması ve uygulanabilirliğinin son tür bağımsız değişken değişimine bağlı olması da geçerlidir.
closed class C<T> { ... }
class D1<U> : C<U> { ... }
class D2<V> : C<V[]> { ... }
class Program
{
int M<X>(C<X> c)
=> c switch
{
D1<X> => 1,
// warning: switch is non-exhaustive. Pattern 'C' is not handled.
};
}
Alt tür kısıtlamaları kapsamlılığı etkilemez
Dil, temel tür ve alt tür tanımındaki tür parametrelerine göre bir alt türün mümkün olup olmadığını belirlemeyi geliştirmez.
closed class C<T>;
class D1<U1> : C<U1>;
class D2<U2> : C<U2> where U2 : struct;
class Program
{
int M1<X>(C<X> c) where X : class
{
// warning: switch is not exhaustive. Pattern 'C<X>' is not handled.
return c switch
{
D1<X> => 1,
};
}
int M2<X>(C<X> c) where X : class
{
return c switch
{
D1<X> => 1,
C<X> => 2, // ok
};
}
}
Örneğin, yukarıdaki anahtar ifadeleri, tüm olası X kısıtlamaları U2ihlal ettiğini fark etmek için yapıyı D2<X> yeterince hassas bir şekilde analiz etmeyin. Bu nedenle, bazılarının D2<X> mümkün olduğunu varsayar ve kullanıcıdan temel türü tüketerek bunu işlemesini ister.
Alt tür olmadığında kapsamlılık
Kapalı bir sınıfın alt türü olmadığında, bunun üzerindeki boş bir anahtar kapsamlı olarak kabul edilmez.
Açıklamalar: Bunun normal kodda "ara durum" olduğu varsayılır. Yazar büyük olasılıkla bu senaryoda bir alt türü bildirmek için bir değişiklik yapacaktır. Bu davranış bir "quirk" değeri alır; "0 alt türün tümü işleniyor" olmasına rağmen dil yine de kullanıcıdan temel türü işlemesini ister.
closed class C;
class Program
{
int M1(C c)
// warning: switch is not exhaustive.
=> c switch
{
};
int M2(C c)
=> c switch
{
C => 1, // ok
};
}
Kapalı türe kısıtlanmış tür parametrelerinin kapsamlılığı
Kapalı bir sınıfla kısıtlanmış bir tür parametresi, kapsamlı denetimler amacıyla kapalı sınıf olarak benzer şekilde kabul edilir.
closed class C;
class D1 : C;
class D2 : C;
class Program
{
int M1<X>(X x) where X : C
=> x switch
{
D1 => 1,
D2 => 2,
};
int M2<X>(X x) where X : C
=> x switch
{
D1 => 1,
D2 => 2,
C => 3, // error: 'C' is subsumed by the previous cases
};
}
Kapalı bir sınıfın alt türlerini belirleme
Kapalı sınıf türleri üzerindeki anahtarların kapsamlılığı, anahtarın giriş kapalı sınıf türünün alt türleri kümesi üzerinde kapsamlı olup olmadığını denetleyerek belirlenir.
Kapalı bir sınıfın alt tür kümesi S aşağıdaki şekilde belirlenir:
- Belirli bir kapalı türü için
CC₀özgün tanımı olsun. - Temel türü özgün tanımı
C₀olan her alt tür bildirimiS₀için, temel türüColan bir yapıSolup olmadığını belirleyin. - Böyle bir
Svarsa, alt tür kümesine dahil edilir.
Kapalı sınıfların arabirim dönüştürülebilirliği
Kapalı bir sınıfın, tüm alt türleri korumalıysa veya korumalı hiyerarşisi varsa, korumalı bir hiyerarşisi olduğu söylenir. Diğer bir ifadeyle, genişletilmiş hiyerarşideki tüm sınıflar korumalı veya kapalıdır.
Kapalı bir sınıfın korumalı hiyerarşisi olduğunda , arabirim dönüştürülebilirlik kısıtlaması getirilir. Bu, hiçbir zaman başarılı olmayacak arabirim türüne dönüştürme girişimini önler.
Bu kısıtlama, doğası gereği korumalı bir sınıf türünden arabirim türüne açık başvuru dönüştürmeye benzer. Bkz . §10.3.5 Açık başvuru dönüştürmeleri.
var c = new C();
var i = (I)c; // error
closed class C { }
sealed class D1 : C { }
sealed class D2 : C { }
interface I { }
ve alt türleri tarafından C uygulanan arabirim kümesini özyinelemeli olarak toplayarak açık başvuru dönüştürmesinin 'den CI var olup olmadığını belirleriz. Arabirim kümesi öğesini içeriyorsa Ive C uygulamazsa I, açık başvuru dönüştürmesi 'den ' C e Ivarıyor demektir. (uygulamasının C uygulanması Idurumunda bunun yerine örtük bir başvuru dönüştürmesi kullanılabilir.)
Düşürme
Kapalı sınıflar, kullanan bir derleyici tarafından tanınmalarına izin vermek için bir IsClosedType öznitelikle oluşturulur.
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class IsClosedTypeAttribute : Attribute { }
}
Diğer dillerden/derleyicilerden alt stili engelleme
Kapalı sınıflar, kapalı sınıfları desteklemeyen dillerden devralınmamalıdır. Bu, kapalı sınıfların tüm oluşturucularına eklenerek [CompilerFeatureRequired("ClosedClasses")] gerçekleştirilir.
// Authoring assembly, built with .NET 10 SDK
closed class C1
{
public C1() { }
public C1(int param) { }
}
// Consuming assembly, built with .NET 8 SDK
class C2 : C1
{
public C2() { } // error: 'C1.C1()' requires compiler feature "ClosedClasses"
public C2() : base(42) { } // error: 'C1.C1(int)' requires compiler feature "ClosedClasses"
}
meta veri "görünümü" C1:
[IsClosedType]
class C1
{
[CompilerFeatureRequired("ClosedClasses")]
public C1() { }
[CompilerFeatureRequired("ClosedClasses")]
public C1(int param) { }
}
"Gerekli üyeler" özelliğinin aksine, DerleyiciFeatureRequiredAttribute'a ek olarak bir ObsoleteAttribute gösterilmediğini unutmayın. Yalnızca ikincisi yayılır.
Birden Çok DerleyiciFeatureRequiredAttributes
Aşağıdaki gibi bir senaryoda, derleyici sembolle ilgili her gerekli özellik için ayrı CompilerFeatureRequiredbir ' i yayar:
closed class C1
{
public C() { }
public required string P { get; set; }
}
// Metadata:
class C1
{
[Obsolete("Types with required members are not supported in this version of your compiler")]
[CompilerFeatureRequired("RequiredMembers")]
[CompilerFeatureRequired("ClosedClasses")]
public C1() { }
}
Dezavantajları
- Var olan bir sınıfa değiştirici eklemek
closedveya kapalı bir sınıftan ek türetilmiş sınıf eklemek hataya neden olan bir değişiklik olabilir. Kapalı bir sınıfı yayımlamadan önce yazarın tüketicileriyle ima ettiği uzun vadeli sözleşmeyi göz önünde bulundurması gerekir.
Alternatives
- Yeni
closeddeğiştirici yerine, kapalı bir sınıf bir[Closed]öznitelikle belirlenebilir. - Alt öğelere izin verilen kapsam, bir dosyaya (C# dilinde çok fazla emsal içermeyecek olsa da) veya kapalı sınıfın iç içe sınıflar olarak gövdesine daraltılabilir.
- İzin verilen kapalı alt öğeler kümesi, bildirimlerin nerede oluştuğuna göre örtük yerine bir liste olarak verilebilir. Bu, sınıfların diğer derlemelere eklenmesine izin verir.
İsteğe bağlı özellikler
- Arabirimlerin kapatılmasına da izin verilebiliyor. Kurallar çok benzer olurdu.
Açık sorular
N/A
C# feature specifications