Access Modifiers — Erişim Belirleyiciler — C#

C# programlama dilinde, erişim belirleyiciler (access modifiers), sınıfların, metotların, değişkenlerin ve diğer üyelerin erişim seviyelerini belirlemek için kullanılır. Bu belirleyiciler, nesne yönelimli programlamanın temel prensiplerinden biri olan kapsüllemeyi (encapsulation) sağlamak amacıyla önemli bir rol oynar.
Temelde dört tür erişim belirleyici vardır: public, internal, protected, ve private. Bunların yanı sıra, daha az bilinen üç erişim belirleyici daha bulunmaktadır: protected internal, private protectedve file.
Genel olarak;
- Erişim belirleyicilerinin önemi.
- Sınıf ve sınıf içerisindeki üyelere erişmek isteyeceğimiz yerler üzerinde duracağız.
- Erişim belirleyicileri nerelerde tanımlayabileceğimize ve tanım kısıtlarına değineceğiz.
- Erişim belirleyicilerinin hepsini değerlendireceğiz.
- Erişim belirleyiciler belirlenmez/tanımlanmazlarsa varsayılan olarak hangi erişim belirleyicinin işaretlendiğini göreceğiz.
Erişim Belirleyiciler Neden Önemldir?
Kapsülleme (Encapsulation): Nesne yönelimli programlamada, bir sınıfın iç verilerini ve işlevlerini dış dünyadan korumak ve gizlemek temel bir prensiptir. Erişim belirleyiciler, sınıfın hangi veri ve metodlarının dış dünyadan erişilebilir olacağını, hangilerinin ise sınıf içinde gizli kalacağını belirleyerek bu kapsüllemeyi sağlar.
Güvenlik: Uygulamanın önemli veya hassas verileri yanlışlıkla değiştirilmesini veya kötüye kullanılmasını önlemek için erişim belirleyiciler kullanılır. Sınırlı erişim, veri bütünlüğünün korunmasına yardımcı olur.
Bakım Kolaylığı: Erişim belirleyicileri, hangi sınıf veya metodun başka bir sınıf veya metot tarafından kullanılabileceğini net bir şekilde tanımlar, bu da geliştirme sürecini daha öngörülebilir ve yönetilebilir hale getirir.
Daha Temiz Arayüzler: Bir sınıfın dışa açık arayüzünü sadece gerekli metod ve verilerle sınırlamak, diğer geliştiricilerin o sınıfı nasıl kullanacaklarını daha kolay anlamalarını sağlar.
Hata Yönetimi: Yanlışlıkla istenmeyen bir metodun çağrılmasını veya bir değişkenin değiştirilmesini engelleyerek, programınızdaki potansiyel hataların önüne geçilebilir.
Erişim belirleyiciler, programın güvenliğini, esnekliğini ve genel kalitesini artırma amacı taşırlar.
Sınıflara ve Üyelere Erişilmek İstenen Yerler
Erişim belirleyicileri anlamak için öncelik olarak sınıf veya sınıf içerisindeki üyelere erişmek istediğimiz yerleri genel olarak bir ele almak faydalı olacaktır.
- Aynı sınıf içerisinden erişim ihtiyacı.
- Aynı assembly altında farklı sınıflardan erişim ihtiyacı.
- Farklı assembly altındaki sınıflardan erişim ihtiyacı.
- Aynı dosya içerisinden erişim.
Assembly ile kastedilen, aynı solution altındaki birbirinden farklı console application, class library, web application, web api vb. projeler, farklı namespace’ler olarak ifade edilebilir.
Bu şekli ile 3 farklı bölümden erişim ihtiyacının olduğu söylenebilir. Burada her ne kadar sadece sınıf ifadesi kullanılsada class, interface, enum, struct gibi yapılarıda sınıf için geçerli olanlar kapsamaktadır. Anlatımın devamında bunların hepsi için sınıf üzerinden ilerlenecektir.
Not: Farklı assembly’lerden erişilebilen erişim belirleyiciler için ilgili assembly’nin referans olarak gösterilmiş olması gerekmektedir. Aksi takdirde public gibi geniş tanımlı erişim belirleyici bile olsa ilgili sınıf veya üyeye erişilemeyecektir. ProjectExampleA içerisindeki bir sınıfa ProjectExampleB içerisinden erişebilmek için öncelik olarak referans olarak projeye eklenmesi gerekmektedir.
Tanımlama Kısıtları
Sınıflar için genel olarak public ,internal vefile erişim belirleyicileri ile işaretlenmektedirler. Diğer erişim belirleyicilerin koruma seviyeleri yüksek olduğu için sınıf seviyesinde işaretleme yapılamazlar.
Bunun dışında kalan diğer tüm erişim belirleyiciler sınıf içerisindeki üyelerde tanımlaması yapılabilir burada üyeler için herhangi bir kısıt yoktur.
Erişim Belirleyiciler
- Public
Bu erişim belirleyici, sınıf veya sınıf içerisindeki üye için herhangi bir yerden erişilebilir olduğunu belirtir. Yani, tanımlandığı assembly’nin (uygulamanın çalıştırılabilir kod kütüphanesi) içinden veya dışından erişim mümkündür. Herhangi bir sınırlaması yoktur ve en geniş erişim belirleyicidir.
namespace ExampleProjectA
{
public class Product
{
public string Code;
public string Name;
}
}
namespace ExampleProjectA
{
public class Program
{
static void Main()
{
//Public olan sınıfa direkt olarak erişim.
Product product = new();// Public olan üyelere direkt olarak erişim.
product.Code = "PX-0";
product.Name = "Kuma";
Console.WriteLine($"Product : {product.Code} - {product.Name}");
}
}
}
// Product : PX-0 - Kuma
namespace ExampleProjectB
{
public class Program
{
static void Main()
{
//Public olan sınıfa direkt olarak farklı bir assembly'den erişim
Product product = new();// Public olan üyelere direk olarak farklı bir assembly'den erişim
product.Code = "PX-0";
product.Name = "Kuma";
Console.WriteLine($"Product : {product.Code} - {product.Name}");
}
}
}
// Product : PX-0 - Kuma
ExampleProjectA altında tanımlanmış olan Product hem ExampleProjectA içerisinden erişilebilirken hem de ExampleProjectB altından erişilebilir. Herhangi bir şekilde erişim sınırlaması yoktur.
Internal
Bu belirleyici, sınıf veya sınıf içerisindeki üyeye yalnızca bulunduğu assembly içinden erişilebileceğini belirtir. Diğer bir deyişle, aynı proje içerisindeki diğer kodlar bu üyelere erişebilir, ancak proje dışından erişim sağlanamaz. Bu, genellikle projenin iç detaylarını dışarıdan gizlemek için kullanılır.
Az önceki örneğimizdeki Product sınıfını internalolarak ayarlarsak ve farklı bir Assembly’den erişmeye çalışırsak sadece ExampleProjectA assembly’si altında erişilebilir olacak ve örneğinExampleProjectB assembly’si içerisinde herhangi bir yerden erişemeyeceğiz.
namespace ExampleProjectA
{
internal class Product
{
public string Code;
public string Name;
}
}
namespace ExampleProjectB
{
public class Program
{
static void Main()
{
// Product nesnesi internal olarak tanımlı olduğu için
// Nesneye bu alandan erişilemiyor.
// Aynı şekilde Product public olsa erişim sağlanabilirdi
// ancak üyelerden biri internal olsa idi
// ilgili üyeye erişim sağlanamayacaktı.
}
}
}
Private
Bu belirleyici, sınıf içerisindeki üyenin sadece tanımlandığı sınıf içinden erişilebileceğini belirtir. Yani, yalnızca o sınıfın üyeleri bu private olarak işaretlenmiş üyeleri kullanabilir. Bu, veri gizliliğini ve sınıf içi kapsüllemeyi sağlamak için kullanılır.
Sınıflar tanımlanırken privateolarak işaretlenemezler. Mantıklı bir şekilde düşündüğümüzde de erişilemeyen bir sınıfın içindeki kodların bir faydası yoktur.
namespace ExampleProjectA
{
public class Product
{
public string Code;
public string Name;
public int Quantity;
public decimal Cost;
private decimal GetTotalCost()
{
/* ... Codes ... */
// Bu metota Product class'ı dışında hiç bir yerden erişim sağlanamaz
// Sınıf içerisinde farklı üyeler private olarak işaretlenmiş
// üyelere erişebilir.
}
}
}
Protected
Bu belirleyici, sınıf içerisindeki üyeye sadece tanımlandığı sınıf içinden veya o sınıftan türetilmiş alt sınıflardan erişilebileceğini belirtir. Bu, bir sınıfın veya üyenin türetilmiş sınıflar tarafından kullanılmasını ama dış dünyadan korunmasını sağlar.
Genel olarak private ile aynı mantığa sahiptir. İstisna olarak kalıtım alınan sınıflardan da erişimine izin verilmiştir. Sınıflar tanımlanırken protectedolarak işaretlenemezler.
namespace ExampleProjectA
{
public class Product
{
public string Code;
public string Name;
public int Quantity;
public decimal Cost;
protected decimal GetTotalCost()
{
/* ... Codes ... */
// Bu metota Product class'ı dışında hiç bir yerden erişim sağlanamaz
// Sınıf içerisinde farklı üyeler protected olarak işaretlenmiş
// üyelere erişebilir. Kalıtım alan bir sınıf olursada yine erişebilir.
}
}
}
namespace ExampleProjectA
{
public class ElectronicProduct : Product
{
public decimal CalculateTax()
{
// GetTotalCost() protected olduğu ce Product tan kalıtım aldığımız
// için erişebilmekteyiz.
int totalCost = GetTotalCost();
/* ... Other Codes ... */
}
}
}
Protected Internal
Bu erişim belirleyici, sınıf içerisindeki üyeye tanımlandığı sınıfın içinden, türetilmiş sınıflardan ve aynı assembly içindeki diğer sınıflardan erişilebilir olduğunu belirtir. Yani, protected internalerişim belirleyicisiyle tanımlanmış bir üye, hem protected hem de internal belirleyicilerinin sağladığı erişim avantajlarını birleştirir. Bu, hem türetilmiş sınıflar aracılığıyla hem de aynı assembly içinde geniş erişime izin verir. Sınıflar tanımlanırken protected internalolarak işaretlenemezler.
Private Protected
Bu erişim belirleyici, sınıf içerisindeki üyeye yalnızca tanımlandığı sınıftan veya o sınıftan türetilen ve aynı zamanda tanımlandığı assembly içinde bulunan sınıflardan erişilebilir olduğunu belirtir. private protected belirleyicisi, private ve protected belirleyicilerinin özelliklerini birleştirir, ancak erişimi yalnızca aynı assembly içindeki türetilmiş sınıflarla sınırlar. Bu, daha dar bir erişim kontrolü sağlar ve belirli bir assembly içindeki türetilmiş sınıflar için gizlilik sunar.
protected örneğinde kalıtım alan her sınıftan erşim sağlanabiliyordu. private protected ile ise farklı assembly’lerden erişimi kısıtlamış oluyoruz. Sınıflar tanımlanırken private protectedolarak işaretlenemezler.
File
C# 11 ile birlikte tanıtılan file anahtar kelimesi, bir tür erişim belirleyicisi olarak kullanılır. file belirleyicisi, görünürlüğünü yalnızca tanımlandığı dosyaya sınırlar.
namespace ExampleProjectA
{
file class Product
{
public int Code() => "PX-0";
}
public class Printer
{
public void PrintCode()
{
Console.WriteLine($"Product Code : {product.Code}");
}
}
}
Product file olarak işaretlendiği için sadece aynı dosya içerisinde Printer gibi tanımlanmış sınıflar içerisinde kullanılabilir. Farklı bir sınıf veya farklı bir assembly altındaki sınıftan erişim sağlanamaz.
Sınıflara (class) ve sınıf içerisindeki üyelere (members) erişim seviyelerine bakılırken ilk olarak sınıfın erişim belirleyicisine bakılır. Yani public olarak bir üye tanımlamış olsakta bağlı olduğu sınıf internal ise farklı bir assembly içerisinden sınıfa erişebilsekte ilgili üyeye erişim sağlayamayız.
Erişim Belirleyici Belirlenmezse/Tanımlanmazsa
Eğer erişim belirleyiciler belirtilmezse, varsayılan olarak belirli erişim belirleyiciler atanır. Sınıf tanımlamaları için varsayılan olarak internal erişim belirleyicisi kabul edilir. Bu, sınıfın yalnızca bulunduğu assembly içinde erişilebilir olduğu anlamına gelir.
Sınıf içerisindeki üyeler için ise varsayılan olarak private erişim belirleyicisi kabul edilir. Yani üyelere sadece tanımlandıkları sınıf içinden erişilebilir.
class Employee
{
/* ... Codes ... */
}
// Yukarıdaki kullanım varsayılan olarak aşağıdakine eşdeğerdir
// Zaten internal kullanacak iseniz özel olarak yazmanıza gerek yok
// varsayılan olarak bunu alacaktır
internal class Employee
{
/* ... Codes ... */
}
Sınıf içerisindeki örnekleri inceleyecek olursak.
public class Employee
{
int GetCalculateAge()
{
/* ... Codes ... */
}
}
// Yukarıdaki kullanım varsayılan olarak aşağıdakine eşdeğerdir
public class Employee
{
private int GetCalculateAge()
{
/* ... Codes ... */
}
}
