C# Encapsulation (kapsülleme) ve Records

Leader-TR

Üye
11 Ağu 2018
183
50
Sanane
Encapsulation (kapsülleme)
Kapsülleme nesnelerimizde ki alanları(field) kontrollü bir şekilde dışarıya açıp kapatmamıza yarayan bir yapıdır. Nesnelerin yanlış kullanımı önlemek için erişim kısıtlaması uygular.
Kapsülleme 2 şekilde uygulanır.
  1. Metod yardımı ile
  2. Property yardımı ile
C#:
class Myclass
{
    private int x;
    // Göndereceğimiz veriyi burada kontrol ediyoruz.
    public int XGet()
    {
        return this.x;
    }
    
    // Dışarıdan alacağımız veriyi buradan kontrol ediyoruz.
    public void XSet(int value)
    {
        this.x = value;
    }
}
Kodda metod yardımı ile bir kapsülleme yaptık. Bu şekilde dışarıdan alınan veriyi ve dışarıya verdiğimiz veriyi kontrol edebiliriz. Bu yöntem eski bir yöntemdir, şimdi property ile nasıl yapılıyormuş ona bakalım.
C#:
class Myclass
{
    private int _x;

    public int X
    {
        get { return _x; }
        set { _x = value; }
    }
}
Bu da property yardımı ile oluşturduğumuz kapsülleme örneğidir. Yukarıda da dediğim gibi kapsülleme field'ları dışarıya kontrollü bir şekilde açmamızı sağlayan bir yapıdır. Bir field'ı sadece salt okunur yapmak isteyebiliriz yada dışarıya veriyi birtakım işlemler uyguladıktan sonra aktarmak isteyebiliriz işte bu ve benzeri durumlar için kapsülleme tekniğini kullanırız. Kapsüllemeyi daha iyi anlayabilmek için property konusunu internette araştırabilirsiniz.

Records

Record yapısını öğrenmemiz için önce Init-Only Properties özelliğini bilmemiz lazım.

Init-Only Properties

Bu özellik bir nesnenin propery'lerine ilk değerinin verilmesi ve bu değerin değiştirilmemesini garanti altına alan bir özelliktir. Bu özellik read-only bir property yapısına benzemekte ama read-only bir property özelliğine sahip bir nesneyi oluştururken property'lerine ilk değerini veremezsin. Nesneyi oluştururken property'lere ilk değerini verebilmemiz için Init-Only Properties özelliğini kullanmalıyız. Yani Init-Only Properties, hem property'i read-only yapıyor, hemde nesneyi oluştururken property'lere ilk değer vermemizi sağlıyor.

C#:
class Program
{
    static void Main(string[] args)
    {
        Film film = new Film()
        {
            adı = "Atların intikamı",
            imdb = 1
        };
            
    }
}


class Film
{
    public string adı { get; init; }
    public int imdb { get; init; }
}

Yukarıdaki Init-Only Properties örneğidir. Gördüğünüz gibi init özelliği sayesinde property'e değeri nesneyi tanımlarken verdik ve property'ler read-only oldu.

Ayrıca readoly olarak tanımlanmış bir property'de init özelliğini kullanabiliriz.

C#:
class Film
{
    private readonly string adı;
    private readonly int imdb;
        
    public string Adı
    {
        get { return adı; }
        init { adı = value; }
    }

    public int Imdb
    {
        get { return imdb; }
        init { imdb = value; }
    }
}

readonly olarak tanımlanmış bir property'i init sayesinde nesne oluştururken ilk değer almasını sağlayabiliriz.

Oluşturduğumuz bir nesnenin bütün değerleri bütünsel olarak değişmemesini istiyorsak records yapısını kullanmalıyız. Record bir nesnenin tamamen sabit ve değişmez olmasını sağlayan ve bunu güvence altına alan bir yapıdır. Record sayesinde bu yapının nesnesinden ziyade sabitlediği değerleri ön plana çıkıyor. Class'larda tanımlanan bütün yapıları record'larda da tanımlayabiliriz.

C#:
class Program
{
    static void Main(string[] args)
    {
        MyRecord x1 = new MyRecord()
        {
            MyProb = 5
        };
        MyRecord x2 = new MyRecord()
        {
            MyProb = 5
        };
            
        Film x3 = new Film()
        {
            MyProb = 5
        };
        Film x4 = new Film()
        {
            MyProb = 5
        };

        Console.WriteLine(x1 == x2);
        Console.WriteLine(x3 == x4);

    }
}

record MyRecord
{
    public int MyProb { get; set; }
}
    
class Film
{
    public int MyProb { get; set; }
}

Kod:
True
False
Yukarıda records ve class'ın farkını gösteren bir kod yazdık. Burada class'tan üretin ve içindeki değerler aynı olan nesneleri karşılaştırdığımızda nesne ön planda olduğu için false değeri döner, record'dan üretilen iki nesneyi karşılaştırdığımızda ise nesneler ön planda olduğu için true değeri dönecektir. Yani kısaca record nesneyi, değer ön planlı yapmaktadır. Record'u read-only ve oluşturulduğu anda tanımlamak istiyorsak init kullanmalıyız. Çünkü record kullanıyorsan değeri ön planda tutarız, değer ön planlı bir yapı kullandıysan çoğunlukla değerlerinin değişmesini istemezsin bundan dolayı da init kullanırız.
Örnek kullanım:

C#:
class Program
{
    static void Main(string[] args)
    {
        MyRecord x1 = new MyRecord()
        {
            MyProb = 5,
            MyProb1 = 4
        };

    }
}

record MyRecord
{
    public int MyProb { get; init; }
    public int MyProb1 { get; init; }
}
Bu işlemlerin hepsini class'la da yapılabilir ama çok property bulunan, salt okunur class'tan ürettiğimiz bir nesnesin bir özelliği farklı bir nesne oluşturmak istersek bütün property'lere tekrardan değer vererek yeni bir nesne oluşturmamız gerekecektir. Çok property bulunan bir class'tan böyle bir nesne oluşturmamız çok can sıkıcı ve zorlayıcı olacaktır. İşte tam bu durumda class yerine record kullanmamız daha uygun olacaktır. Recordun with özeliği sayesinde bu durumu kolay bir şekilde halledebiliriz.

C#:
class Program
{
    static void Main(string[] args)
    {
        Film f1 = new Film()
        {
            isim = "cehennem melekleri",
            saat = "12.00",
            salonNo = 2
        };

        Film f2 = f1 with { salonNo = 4 };

        Console.WriteLine(f2.salonNo);

    }
}

record Film
{
    public string isim { get; init; }
    public string saat { get; init; }
    public int salonNo { get; init; }
}

Kod:
4
Burada with sayesinde salonNo'sunu değiştirdiğimiz bir kopyayı oluşturduk. Record'un bu özelliği bize baya bir avantaj sağladı.
Bunu class ile yapmanın daha zahmetli bir yolu daha bulunmaktadır.

C#:
class Program
{
    static void Main(string[] args)
    {
        Film f1 = new Film()
        {
            isim = "cehennem melekleri",
            saat = "12.00",
            salonNo = 2
        };
        Film f2 = f1.With(4);
            

        Console.WriteLine(f2.salonNo);

    }
}

class Film
{
    public string isim { get; set; }
    public string saat { get; init; }
    public int salonNo { get; init; }

    public Film With(int salonNO)
    {
        return new Film()
        {
            isim = this.isim,
            saat = this.saat,
            salonNo = salonNO

        };
    }
}
Bu yöntem record'a göre çok daha karmaşık ve zordur.

Positional Record

Record içerisindeki constructor, deconstructor gibi özel tanımlı metodların kullanımlarını özelleştirerek kullanılmasını sağlamaktadır.
C#:
record MyRecord(int x, int y)
{

}
Positional record bu şekilde tanımlanır. Bu tanımlama sonucu hem constructor hem de deconstructor oluşturmuş olduk.
C#:
class Program
{
    static void Main(string[] args)
    {
        // Contructor'u tetikledik.
        MyRecord m = new MyRecord(1, 2);

        // Decontrocturu kullandık.
        var (a, b) = m;

    }
}

record MyRecord(int x, int y)
{
        
}

Yukarıda Positional record kullandığımızdan otomatik olarak x ve y propertyleri init olarak oluştu. Daha sonra nesne yaratırken parametre vererek contructor özelliğini kullandık. Hemen altında ise decontructor kullanarak nesne oluştururken verdiğimiz x ve y değerlerini a ve b değişkenlerine atadık.

Bu record'larda bulunan constructorlar overloading edilebilirler. Ama Positional recordın yarattığı constructoru tetiklemek zorunludur.
C#:
class Program
{
    static void Main(string[] args)
    {
        // Contructor'u tetikledik.
        MyRecord m = new MyRecord();

        // Decontrocturu kullandık.
        var (x, y) = m;

    }
}

record MyRecord(int x, int y)
{
    public MyRecord() : this(3, 4)
    {
            
    }
        
}
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.