Herkese merhaba. Bir önceki yazımda değer ve referans tipleri anlatmıştım. Bu yazıda da static class yapısını inceleyeceğiz. C# içerisinde nesne yönelimli programlamada static class’ları kullanarak daha fonksiyonel bir programlama yapabiliriz. Genellikle tek bir tane üretmek istediğimiz nesnelerde static yapısını tercih ederiz. Örneklere github hesabımdan ulaşabilirsiniz.

Static Class

Static classlar, içinde bulunduğu sınıftan nesne oluşturulmadan veya hiçbir referans olmadan kullanılabilen üyeler static olarak nitelendirilir. Tasarımda özellikle tek bir instance olması istenen sınıflar static olarak işaretlenir. Static olarak işaretlediğimiz classlardan hiçbir şekilde nesne türetemeyiz.

Static sınıflar içerisinde normal bir değişken tanımlaması yapamayız. İçerisinde bulundurduğu üyelerin hepsi static olmak zorundadır. .Net arka planda static class’ın herhangi bir üyesine eriştiğimiz zaman otomatik olarak bir instance oluşturur. Bu nedenle bizim instance oluşturmamıza izin vermez. Örnek olarak bir static class’tan nesne oluşturmaya çalışalım.

Static Class Instance

Şimdi anlattığım teorik bilgileri bir örnek ile pekiştirelim. Örnek olarak; toplama ve çarpma işlemlerini static olarak çalıştıracak bir matematik kütüphanesi tasarlayalım.

internal static class StaticMath
{
    public static int Addition(List numbers)
    {
        int sum = 0;
        foreach (int item in numbers)
        {
            sum += item;
        }
        return sum;
    }

    public static int Multiplication(List numbers)
    {
        int result = 1;
        foreach (int item in numbers)
        {
            result *= item;
        }
        return result;
    }
}
static void Main(string[] args)
{
    Console.WriteLine("Lütfen işlem yapmak istediğiniz sayı adedini giriniz: ");
    int count = int.Parse(Console.ReadLine());
    
    Console.WriteLine("Lütfen sayıları giriniz:");
    List numbers = new List();
    for (int i = 0; i < count; i++)
    {
        numbers.Add(int.Parse(Console.ReadLine()));
    }

    Console.WriteLine("Toplama için 1'i çarpma için 2'yi tuşlayınız:");
    int choice = int.Parse(Console.ReadLine());
    switch (choice)
    {
        case 1:
            Console.WriteLine("Sonuç : " + StaticMath.Addition(numbers));
            break;
        case 2:
            Console.WriteLine("Sonuç : " + StaticMath.Multiplication(numbers));
            break;
        default:
            break;
    }

    Console.ReadKey();
}

Şimdi static değişkenleri inceleyelim. Static değişkenlere de normal değişken türlerindeki gibi, ilk değer ataması yapılmamışsa tipine göre default değer ataması yapılır. Static bir değişkenin her zaman bir değeri vardır. Örnek olarak StaticMath sınıfı içerisine null değer ataması yaptığımız bir değişken tanımlayalım.

internal static class StaticMath
{
    public static string NullString = null;
}
static void Main(string[] args)
{
    Console.WriteLine("String'in değeri: " + StaticMath.NullString == null ? "null": "empty");
    Console.ReadKey();
}

Build ettiğimizde ekrana “empty” yazdığını görürüz. Static sınıflar üzerindeki bellek yapılarını inceleyelim. Static yapılardan çalışma süresinde sadece 1 adet üretilmektedir. Ancak aldığı değer runtime içerisinde değiştirilebilir. Örneğin static class içerisinde bir static property tanımlayalım.

internal static class StaticMath
{
    public static double Pi = 3.14;
    public static void ChangethePitoInt()
    {
        Pi = 3;
    }

}
static void Main(string[] args)
{
    Console.WriteLine("Metot çalışmadan önceki Pİ: " + StaticMath.Pi.ToString());
    StaticMath.ChangethePitoInt();
    Console.WriteLine("Metot çalıştıktan sonraki Pİ: " + StaticMath.Pi.ToString());

    Console.ReadKey();
}

Uygulamayı çalıştırdığımızda aynı statik değerin 3 olarak ekrana geldiğini görürüz. Eğer bu işlemi normal bir class içerisinden yapsaydık ve constructor metoda static değişkenin ilk değer atamasını yapsaydık farklı bir durumla karşılaşmış olurduk. Bu örneği static class içerisine constructor metodu ekleyerek deneyemeyiz. Çünkü static sınıfların sadece 1 adet constructor metodu olur. Bu metot da arkaplanda otomatik olarak .Net tarafından oluşturulmaktadır.

internal class MathClass
{
    public static double PI = 3.14;

    public MathClass()
    {
        PI = 3.1415;
    }
    public void ChangethePitoInt()
    {
        return PI = 3;
    }
}
static void Main(string[] args)
{
    Console.WriteLine("Metot çalışmadan önceki Pİ: " + MathClass.PI.ToString());
    MathClass math = new MathClass();
    Console.WriteLine("Constructor çalıştıktan sonraki Pİ: " + MathClass.PI.ToString());
    math.ChangethePitoInt();
    Console.WriteLine("Metot çalıştıktan sonraki Pİ: " + MathClass.PI.ToString());
    MathClass math1 = new MathClass();
    Console.WriteLine("Constructor çalıştıktan sonraki Pİ: " + MathClass.PI.ToString());
    Console.ReadKey();
}

Static Uyeler

Örnektede gördüğümüz gibi constructor metodu çalıştıktan sonra PI değişkeninin değeri 3.1415 olarak değişir. Bunun nedeni her yeni nesne oluşturulduğunda constructor metodun çalışarak PI değişkeninin değerini 3.1415 olarak set etmesidir. Burada sadece static bir üyeye değer ataması yaptığımız için best practice olarak static constructor metot kullanmalıyız.

Static Constructor

Bu metotlar nesne oluşturduğumuzda sınıfın static üyelerine sadece bir kereliğine değer atamamızı sağlar. Static constructor metotların erişim belirleyicisi olmaz. Her zaman normal constructor metotlardan önce çalışırlar. Parametre almazlar. Sınıftan kaç tane nesne oluşturulursa oluşturulsun sadece bir kere çalışırlar. Bir sınıf sadece bir adet static constructor metoda sahip olabilir.

internal class MathClass
{
    public static double PI = 3.14;

    public MathClass()
    {
        PI = 3.1415;
    }
    static MathClass()
    {
        PI = 3.141592;
    }
    public void ChangethePitoInt()
    {
        return PI = 3;
    }
}
static void Main(string[] args)
{
    Console.WriteLine("Metot çalışmadan önceki Pİ: " + MathClass.PI.ToString());
    MathClass math = new MathClass();
    Console.WriteLine("Constructor çalıştıktan sonraki Pİ: " + MathClass.PI.ToString());
    math.ChangethePitoInt();
    Console.WriteLine("Metot çalıştıktan sonraki Pİ: " + MathClass.PI.ToString());
    MathClass math1 = new MathClass();
    Console.WriteLine("Constructor çalıştıktan sonraki Pİ: " + MathClass.PI.ToString());
    Console.ReadKey();
}

Static Constructor

Önceki yazıda da incelediğimiz reference ve value type üyeleri içerisinden sadece sınıflar static olarak tanımlanabilir. Static sınıflar kalıtım alamaz ve vermezler. Static bir tip herhangi başka bir class içerisindeki bir prop’un tipi veya metodun geri dönüş tipi olamaz. Ayrıca static class tipinden field tanımlanamaz ve metoda parametre olarak verilmez. Static metot içerisinden non-static field’a erişemeyiz.

Static Members

Normal class içerisinde static üyeler ve metotlar varsa, static üyeler kendi arasında çalışır. Static üyeler class’a hizmet ederken normal üyeler nesneye hizmet eder.

Constants (değişmezler) bilinçsiz (implicitly) olarak static olarak tanımlanırlar. Ancak readonly olarak tanımlanan değişkenler açıkça belirtilmedikçe static değildir.

Benim static tipi için notlarım bu kadar. Özellikle bilinçli nesne yönetimi yapılabilmesi için bu konunun bilinmesi gerektiğini düşünüyorum. Bir sonraki yazıya kadar kendinize çok iyi bakın! 😊