Erişim belirleyiciler bir tipi ya da üyeyi hangi kodun kullanabileceğine karar verir. Bir sınıfın, diğer kodun dayandığı kısmı (public yüzeyi) değiştirmekte serbest olduğu kısımdan (iç yapısı) ayırmasının yolu budur. C#'ta altı tane vardır, bir de hiçbirini yazmadığınızda aldığınız varsayılanlar.
Altı belirleyici
| Belirleyici | İçeren tip | Türetilmiş tip, aynı assembly | Diğer kod, aynı assembly | Türetilmiş tip, başka assembly | Diğer kod, başka assembly |
|---|---|---|---|---|---|
public | evet | evet | evet | evet | evet |
protected internal | evet | evet | evet | evet | hayır |
protected | evet | evet | hayır | evet | hayır |
internal | evet | evet | evet | hayır | hayır |
private protected | evet | evet | hayır | hayır | hayır |
private | evet | hayır | hayır | hayır | hayır |
Bir assembly derlenmiş tek bir projedir: ürettiği .dll ya da .exe. "Aynı assembly" "aynı proje" demektir; internal'ın "benim koduma görünür, kütüphanemin kullanıcılarından gizli" olarak çalışmasının nedeni budur.
private ve public: kapsülleme
private üyeler için varsayılandır ve çoğu alan için doğru seçimdir. Sınıf, çağıranların ihtiyaç duyduğunu public metotlar ve property'ler aracılığıyla sunar ve bu metotlar nesnenin verisini tutarlı tutar.
Çıktı:
False
True
Priya: 180
balance private olduğu için onu değiştirmenin tek yolu Deposit ve TryWithdraw'dur ve ikisi de kuralları uygular. Programdaki başka hiçbir kod, nasıl yazılırsa yazılsın, negatif bir bakiye oluşturamaz. Kapsüllemenin kazandırdığı budur: kurallar tek bir yerde yaşar.
private nesne başına değil tip başınadır. Account'un bir metodu farklı bir Account örneğindeki other.balance'ı okuyabilir; Equals ve karşılaştırma metotları genellikle böyle yazılır.
protected: türetilmiş sınıflara görünür
protected bir üye dış dünyadan gizlidir ama bildiren sınıftan kalıtım alan sınıflar tarafından kullanılabilir.
Çıktı:
Sam: 4000.00
Rita: 6400.00
İnsanları şaşırtan bir kural vardır. Manager içinde baseSalary'yi this üzerinde ya da başka bir Manager üzerinde kullanabilirsiniz, ama rastgele bir Employee üzerinde kullanamazsınız:
class Manager : Employee
{
public decimal Compare(Employee other)
{
return baseSalary - other.baseSalary;
// error CS1540: Cannot access protected member 'Employee.baseSalary' via a qualifier
// of type 'Employee'; the qualifier must be of type 'Manager' (or derived from it)
}
}
Nedeni: other, Employee'den türeyen bir Contractor da olabilir ve protected size hiyerarşinin kardeşlerinizin dalına değil kendi dalınıza erişim verir.
Protected bir alan her türetilmiş sınıfı sonsuza kadar o alana bağlar. Birçok kod tabanı protected bir property ya da metodu tercih eder veya alanları private tutup türetilmiş sınıflara yalnızca ihtiyaç duyduklarını verir.
internal: assembly içinde görünür
internal üyeler ve tipler aynı projedeki her kod tarafından kullanılabilir, dışarıdaki hiçbir şey tarafından kullanılamaz. Bir kütüphane onu public sınıflarının dayandığı yardımcılar için kullanır:
// In the MyShop.Pricing library project
public class PriceCalculator
{
public decimal Total(Cart cart) => TaxRules.Apply(cart.Subtotal);
}
internal static class TaxRules // callers of the library cannot see this class
{
internal static decimal Apply(decimal amount) => amount * 1.2m;
}
Hiçbir belirleyici yazmadığınızda üst seviye tipler internal'dır. Bir sınıf kütüphanesinde public işaretlemeyi unuttuğunuz bir sınıfın ona referans veren projede "kayıp" olmasının nedeni budur.
Birim test projeleri ayrı assembly'lerdir, bu yüzden onlar da internal kodu göremez. Standart çözüm kütüphanedeki bir özniteliktir:
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyShop.Pricing.Tests")]
protected internal ve private protected
Bu ikisi önceki belirleyicileri zıt yollarla birleştirir ve adları kolayca karıştırılır:
protected internal, protected ya da internal'dır: aynı assembly'deki her kod ve başka assembly'lerdeki türetilmiş sınıflar. Daha geniş olanıdır.private protected(C# 7.2), protected ve internal'dır: yalnızca aynı assembly'de de bulunan türetilmiş sınıflar. Daha dar olanıdır; genişletme noktaları kütüphanenizin içinde kalması gereken bir temel sınıf içindir.
public class ReportBase
{
protected internal string Title; // same assembly, or subclasses anywhere
private protected int RowLimit = 500; // subclasses in this assembly only (C# 7.2)
}
Hiçbir şey yazmadığınızda varsayılanlar
| Nerede | Varsayılan | İzin verilenler |
|---|---|---|
| Bir namespace içinde bildirilen tip | internal | public, internal, file (C# 11) |
| Bir sınıfın üyesi | private | altısı da |
| Bir struct'ın üyesi | private | public, internal, private (struct'lardan kalıtım alınamaz) |
| İç içe tip | private | altısı da |
| Interface üyesi | public | C# 8'den beri açık belirleyicilere izin verilir |
| Enum üyesi | public | hiçbiri |
Açık olmak tek bir kelimeye mal olur ve sonraki okuyucu için bir soruyu ortadan kaldırır; bu yüzden çoğu stil kılavuzu varsayılanla eşleşse bile belirleyiciyi yazmayı ister.
Erişimci seviyesinde erişim
Bir property ya da indeksleyici, erişimcilerinden birine property'nin kendisinden daha dar bir belirleyici verebilir:
Çıktı:
report.pdf: 100%
Erişimcinin belirleyicisi property'ninkinden daha kısıtlayıcı olmalıdır ve iki erişimciden yalnızca birinin belirleyicisi olabilir.
Tutarsız erişilebilirlik
Public bir üye kendisinden daha az görünür bir tipi dışa açamaz, çünkü çağıranlar adını anmalarına izin verilmeyen bir şey alırdı:
internal class Discount { }
public class Checkout
{
public Discount Current() => null;
// error CS0050: Inconsistent accessibility: return type 'Discount' is less accessible than method 'Checkout.Current()'
}
Aynı kural parametre tipleri için CS0051, property tipleri için CS0053 verir. Tipi üye kadar görünür ya da üyeyi tip kadar gizli yaparak düzeltin.
Bir belirleyici seçmek
Çalışan en kısıtlayıcı belirleyiciyle başlayın ve onu yalnızca bir çağıran ihtiyaç duyduğunda genişletin. Bir şeyi sonradan daha görünür yapmak kolaydır ve kimseyi bozmaz; bir şeyi daha az görünür yapmak onu kullanan her çağıranı bozar. Uygulamada: alanlar private, sınıfın amacını oluşturan üyeler public, yardımcılar private ve yalnızca kütüphaneye ait tipler internal.
Sıkça Sorulan Sorular
C#'ta erişim belirleyiciler nelerdir?
Altı tane vardır: public (her kod), private (yalnızca içeren tip), protected (içeren tip ve ondan türeyen tipler), internal (aynı assembly'deki her kod), protected internal (aynı assembly ya da her yerdeki türetilmiş tipler) ve private protected (aynı assembly'deki türetilmiş tipler, C# 7.2). C# 11, yalnızca tek bir kaynak dosyada görünen tipler için file'ı ekledi.
C#'ta varsayılan erişim belirleyici nedir?
Bir class ya da struct'ın üyeleri (alanlar, metotlar, property'ler, iç içe tipler) varsayılan olarak private'tır. Üst seviye tipler (doğrudan bir namespace içinde bildirilmiş bir sınıf) varsayılan olarak internal'dır. Interface üyeleri ve enum üyeleri public'tir.
C#'ta protected ne anlama gelir?
protected bir üye kendi sınıfının ve ondan türeyen her sınıfın içinde görünür, ama diğer kodlara görünmez. Türetilmiş bir sınıf onu yalnızca kendi tipi üzerinden kullanabilir: Manager içinde this.baseSalary çalışır, ama başka bir Employee nesnesindeki baseSalary'ye ulaşmak CS1540 hatasıdır.
C#'ta internal nedir?
internal bir tipi ya da üyeyi aynı assembly'deki (aynı projenin derlenmiş .dll ya da .exe dosyası) tüm kodlara görünür, dışarıya ise görünmez yapar. Bir kütüphanenin yardımcı sınıfları public API'sinin dışında tutmasının yolu budur. [assembly: InternalsVisibleTo("MyLib.Tests")] bir test projesinin de onları görmesini sağlar.
"is inaccessible due to its protection level" hatası nasıl düzeltilir?
Bu CS0122 hatasıdır: kod görmesine izin verilmeyen bir üyeyi kullanıyor; çoğu zaman varsayılan private'ta bırakılmış bir alan. Dışarıdaki kodun onu okuması gerekiyorsa public bir property ya da metot sunun; alanı öylece public yapmayın. Başka bir projeden gelen bir tipse muhtemelen internal'dır.