Metotları aşırı yüklemek, aynı isimde fakat imzaları farklı metotlar tanımlayabilmemiz anlamına gelir. Metotların imzaları, aldıkları parametre tipleri ve sayıları ile ilişkilidir. Aşırı yüklenmiş metotlar çağrılırken, gönderilen parametreye göre hangi versiyonun çalışacağına karar verilir.

.Net framework içerisinde aşırı yüklenmiş bir çok metot bulunmaktadır. Consol uygulamalarında sıkça kullandığımız WriteLine metodunun 19 farklı versiyonu bulunmaktadır.

image

Bu 19 versiyonun hepsi geriye void dönerken, aldıkları parametre tipleri veya sayıları değişmektedir.

NOT: Metodun geri dönüş tipi, imzasını etkileyen faktörlerden biri değildir!

Aşağıda bir metodu nasıl  aşırı yükleyebileceğimiz ile ilgili bir kod örneği mevcuttur.

class Program

    {

        static void Main(string[] args)

        {

            AsiriYuklenmisMetot(5);

            AsiriYuklenmisMetot("test");

            AsiriYuklenmisMetot(new SqlConnection());

            AsiriYuklenmisMetot(10, new object());

            Console.WriteLine("Toplam : {0}", AsiriYuklenmisMetot(5, 10, 40));

        }

 

        static void AsiriYuklenmisMetot(int p1)

        {

            Console.WriteLine("{0} tipinde parametre alırım", p1.GetType().ToString());

        }

 

        static void AsiriYuklenmisMetot(string p1)

        {

            Console.WriteLine("{0} tipinde parametre alırım", p1.GetType().ToString());

        }

 

        static void AsiriYuklenmisMetot(SqlConnection p1)

        {

            Console.WriteLine("{0} tipinde parametre alırım", p1.GetType().ToString());

        }

 

        static void AsiriYuklenmisMetot(int p1, object p2)

        {

            Console.WriteLine("{0} ve {1} tipinde parametre alırım", p1.GetType().ToString(), p2.GetType().ToString());

        }

 

        static int AsiriYuklenmisMetot(int p1, int p2, int p3)

        {

            int toplam = p1 + p2 + p3;

            return toplam;

        }

    }

Programı çalıştırdığımızda alacağımız ekran görüntüsü şu şekildedir.

image

SIkça karşılaştığımız senaryolardan biri de, constructor(yapıcı) metotların aşırı yüklenmesi durumudur. Bir nesne örnekleyeceğimiz zaman, yapacağımız ilk değer atamaları farklılık gösterebilir.

Urun adında bir sınıf yazalım ve yapıcı metodunu aşırı yükleyelim.

class Urun

    {

        public int Id { get; set; }

        public string Ad { get; set; }

        public double Fiyat { get; set; }

    }

Bir sınıfa yapıcı metot yazmassak, arka tarafta parametre almayan bir yapıcı metot default olarak tanımlanır. Parametre alan bir yapıcı metot tanımı yaptığımızda, arka tarafta default olarak bir yapıcı metot tanımı yapılmaz.

class Urun

    {

        public int Id { get; set; }

        public string Ad { get; set; }

        public double Fiyat { get; set; }

 

        public Urun(int id, string ad, double fiyat)

        {

            Id = id;

            Ad = ad;

            Fiyat = fiyat;

        }

 

        public Urun(int id, double fiyat)

        {

            Id = id;

            Fiyat = fiyat;

            Ad = "isimsiz";

        }

 

        public Urun()

        {

            // Bu versiyonu tanımlamassak Urun u=new Urun(); gibi bir nesne örnekleme yapamayız.

        }

    }

Main metodu içerisinde Urun tipinden nesneler örnekleyelim.

class Program

    {

        static void Main(string[] args)

        {

            Urun u = new Urun();

 

            Urun u2 = new Urun(1, "Monitör", 200);

            Console.WriteLine(u2.Ad);

 

            Urun u3 = new Urun(2, 45);

            Console.WriteLine(u3.Ad);

        }

    }

Ekran çıktısı aşağıdaki gibi olacaktır.

image



Bir önceki makalemizde ref anahtar sözcüğünün detaylarından bahsetmiştim. out ile parametre göndermek, referans göndermek ile aynıdır.ref anahtar sözcüğünden tek farkı,  parametreye metot içerisinde bir değer atanması zorunluluğudur. Amaç, alınan parametrenin metot içerisinde değer kazandırılarak dışarıya gönderilmesidir.

Basit bir örnek ile incelemeye çalışalım. out parametre alan bir metot alarak, aldığı parametreyi ekrana yazdıran bir metot yazalım.

class Program

    {

        static void Main(string[] args)

        {

            int sayi = 99;

            Test(out sayi);

        }

 

        static void Test(out int sayi)

        {

            Console.WriteLine(sayi);

        }

    }

Test metodu aldığı out parametreyi içeride değer atamadan kullanmaya çalıştığından dolayı aşağıdaki gibi bir hata mesajı ile karşılaşacağız.

Error    1  :  The out parameter 'sayi' must be assigned to before control leaves the current method  

Error    2  :  Use of unassigned out parameter 'sayi' 

Giriştede bahsettiğim gibi, parametreye metot içerisinde değer atamadan kullanmamıza izin verilmemektedir. Zaten out parametrenin farkı da budur. Amaç metot içerisinde değer kazandırılarak, bu değeri dışarıya göndermektir.

Kodumuzu aşağıdaki gibi değiştirerek programı çalıştıralım.

class Program

    {

        static void Main(string[] args)

        {

            int sayi;

            Test(out sayi);

        }

 

        static void Test(out int sayi)

        {

     sayi=99;

            Console.WriteLine(sayi);

        }

    }

Main metodu içerisinde tanımlanan ve herhangi bir değer atanmayan “sayi” adlı değişken, Test metodu içerisinde 99 değerine sahip olmuştur.

image

Şimdi de DiziAnaliz adında bir metot yazalım. Metot parametre olarak bir integer dizisi alsın. Bunun yanında toplam,ortalama,enBuyuk ve enKucuk adında 4 adet out parametre alsın ve içeride bu değişkenlere uygun değerleri atayarak dışarı göndersin.

class Program

    {

        static void Main(string[] args)

        {

            int[] sayilar = { 22, 63, 44, 13, 25, 60, 87, 68, 79 };

           

            int enBuyuk, enKucuk, toplam;

            double ortalama;

           

            DiziAnaliz(sayilar, out toplam, out ortalama, out enBuyuk, out enKucuk);

           

            Console.WriteLine("Eleman sayısı : {0}\nToplam : {1}\nOrtalama : {2}\nEn büyük sayı : {3}\nEn küçük sayı : {4}", sayilar.Length, toplam, ortalama, enBuyuk, enKucuk);

        }

 

        static void DiziAnaliz(int[] dizi, out int toplam, out double ortalama, out int enBuyuk, out int enKucuk)

        {

            enBuyuk = dizi[0];

            enKucuk = dizi[0];

            toplam = 0;

 

            foreach (int sayi in dizi)

            {

                toplam += sayi;

 

                if (sayi > enBuyuk)

                {

                    enBuyuk = sayi;

                }

 

                if (sayi < enKucuk)

                {

                    enKucuk = sayi;

                }

            }

 

            ortalama = (double)toplam / dizi.Length; //sonucu double olarak alabilmek için cast işlemi yaptık. iki integer'ı birbirine böldüğümüzde sonuç küsüratlı çıkarsa, integer'a cast edilerek küsüratı atılır.

        }

    }

Ekran çıktısı aşağıdaki gibi olacaktır.

image



.Net dünyasında temel olarak iki tip parametre vardır. Değer (value) veya referans (referance) geçmek. Parametre olarak değer geçmek, stack’de duran işaretçinin içerisindeki değeri ya da adresi (referans türlü ise) vermek demektir. Referans geçmek ise, işaretçinin ram üzerindeki adresini (işaretçi de ram üzerinde yer kaplar ve bir adresi vardır) vermek anlamına gelir. Örnekler üzerinden ilerleyerek, yaptığımız atamaları sembolize etmeye çalışalım.

Test_int adlı metot yazalım. Parametre olarak bir integer deger alsın ve içeride o integer’ın değerini değiştirsin.

class Program

    {

        static void Main(string[] args)

        {

            int sayi = 40;

            Test_int(sayi);

            Console.WriteLine(sayi);

        }

 

        static void Test_int(int a)

        {

            a = 200;

        }

    }

Programı çalıştırdığımızda sayı adlı değişkenin değerinin 40 olduğunu görürüz. Sebebi basittir. Local değişkenler, tanımlandıkları metot işini bitirdiğinde ram’den düşerler. Durumu sembolize etmeye çalışalım.

image

Main metodu içerisindeki sayı adlı değişkenin ram’deki sembolik şekli yukarıdaki gibidir. Test_int metodu çalıştığında ram’e “a” adında locak bir değişken çıkar ve parametre olarak sayi adlı değişkenin değeri gönderilir. (ref veya out anahtar sözcüklerini kullanmadan parametre geçmek, değer geçmek anlamına gelmektedir.)

NOT: F23 ve F71 benim verdiğim sembolik bir değerdir. Değişkenin ram üzerindeki adresini temsil etmektedir.

image

Test_int metodunun içerisine girildiğinde a adl local değişkenin değeri 200 olur.

image

Daha sonra Test_int metodu işini bitirir ve içerisindeki local değişkenler ram’den düşer.

image

Main metodu kaldığı satırdan çalışmaya devam eder. Bir sonraki adım, “sayi” adlı değişkenin ekrana yazdırılma işlemidir. 40 değerine sahip olduğu için de ekranda 40’ı görmüş olduk.

Şimdi de aynı örneği ref anahtar sözcüğünü kullanarak yapmaya çalışalım. Test_int_ref adında bir metot yazalım. Tek fark, parametrenin ref anahtar sözcüğü ile birlikte verilmesi olacaktır. Yani “sayi” adlı değişkenin değerini değil de, referansını (ram’deki adresini) göndermiş olacağız.

class Program

    {

        static void Main(string[] args)

        {

            int sayi = 40;

            Test_int_ref(ref sayi);

            Console.WriteLine(sayi);

        }

 

        static void Test_int_ref(ref int a)

        {

            a = 200;

        }

    }

Metot bizden integer tipinden bir değer değil de, integer tipinden bir işaretçinin ram’deki adresini beklemektedir. Yani Main metodu içerisinde “sayi” adlı değişkenin direkt olarak kendisini parametre olarak verdiğimizi düşünebiliriz. Test_int_ref adlı metot içerisindeki “a” adlı local değişken, direkt olarak “sayi” değişkenin temsil etmektedir. Şimdi durumu sembolize etmeye çalışalım.

Main metodu çalışmaya başladığında ram’e “sayi” adlı local bir değişken çıkar ve değeri 40’dır.

image

ikinci satıra geçildğinde Test_int_ref adlı metoda çağrı yapılır ve parametre olarak sayı değişkenin referansı verilir.

image

“a” adlı locak değişken, “sayi” adlı değişkeni temsil eder, yani “sayi” değişkenin ram üzerindeki adresini tutar. Dolayısı ile a değişkeni üzerinde yapacağımız herhangi bir işlem direkt olarak “sayi” adlı değişkenin üzerinde de gerçekleşecektir. Metot içerisinde “a” adlı değişkenin değerine 200 atanır.

image

Test_int_ref metodu işini bitirdiğinde “a” değişkeni ram’den düşer.

image

Main metodu çalışmaya kaldığı yerden devam eder. Artık “sayi” değişkeni 200 değerine sahiptir. Dolayısı ile ekran çıktısı aşağıdaki gibi olacaktır.

image

Değer türlü tipler için durum yukarıdaki gibidir. Şimdi de referans türlü tip için bir test yapalım. Urun adında id,ad ve fiyat alanlarına sahip bir sınıf yazalım. Test_urun adında geriye void dönen bir metodumuz olsun. Parametre olarak bir Urun alsın ve aldığı bu Urun’un fiyatını değiştirsin.

class Urun

    {

        public int Id { get; set; }

        public string Ad { get; set; }

        public double Fiyat { get; set; }

 

        public Urun(int id, string ad, double fiyat)

        {

            Id = id;

            Ad = ad;

            Fiyat = fiyat;

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            Urun urun = new Urun(1, "Monitör", 200);

            Test_urun(urun);

            Console.WriteLine(urun.Fiyat);

        }

 

        static void Test_urun(Urun u)

        {

            u.Fiyat = 999;

        }

    } 

Main metodu çalışmaya başladığında ram’e bir Urun nesne örneği çıkar. Ram’de tutulma şeklide sembolik olarak aşağıdaki gibidir.

NOT: K30, M60, B15 sembolik olarak ram’deki adresleri belirtmektedir.

image

ikinci satıra geçildiğinde Test_urun metot çağırılır ve parametre olarak “urun” adlı değişkenin değeri gönderilir. Bu değişkenin değeri, içerisinde tuttuğu adres bilgisidir.

image

Metot içerisinde, parametre olarak gelen Urun’un fiyatına 999 değeri atanır.

image

Test_urun metodu işini bitirdiğinde “u” adlı locak değişken ram’den düşer.

image

Main metodu çalışmaya kaldığı yerden devam eder. “urun” adlı değişkenin işaret ettiği nesnenin fiyat alanında 999 değeri olduğundan ötürü, program çalıştığında ekranda bu değeri görürüz.

image

Bu şekilde bakıldığında referans türlü tiplerde “ref” anahtar sözcüğünün kullanılıp kullanılmamasının sonucu değiştirmeyeceği kanısına varılabilir. Ancak durum gözüktüğü gibi değildir. Urun sınıfı üzerinden başka bir örnek ile devam edelim.

class Urun

    {

        public int Id { get; set; }

        public string Ad { get; set; }

        public double Fiyat { get; set; }

 

        public Urun(int id, string ad, double fiyat)

        {

            Id = id;

            Ad = ad;

            Fiyat = fiyat;

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            Urun urun = new Urun(1, "Monitör", 200);

            Console.WriteLine(urun.Fiyat);

 

            Test_urun2(urun);

            Console.WriteLine(urun.Fiyat);

 

        }

 

        static void Test_urun2(Urun u)

        {

            u = new Urun(2, "laptop", 1500);

            u.Fiyat = 2750;

        }

    }

Main metodu çalıştığında ram’e bir Urun nesnesi çıkar. Urunun fiyatı ekrana yazdırılır.

image

image

urun adlı değişken heap’de adı monitör olan bir nesneyi işaret etmektedir. Test_urun2 adlı metot çağrıldığında “u” adlı local bir değişken ram’e çıkar. Değeri, parametre olarak gelen “urun” değişkenin değeridir. Yani adı monitör olan nesneyi işaret etmektedir.

image

Metot içerisinde yeni bir nesne üretilir ve adresi “u” değişkenine verilir.

image

Daha sonra u adlı değişkenin işaret ettiği nesnenin fiyatına 2750  değeri atanır.

image

Metot işini bitirdiğinde u adlı değişken ram’den düşer.

image

ram’de üzerinde Y99 adresine sahip nesne, stack’de herhangi bir işaretçi tarafından işaret edilmedinden dolayı ram’den düşer. Dolayısı ile P50 adresindeki nesne de aynı sebepten ötürü ram’den düşer.

image

Main metodu çalışmaya kaldığı yerden devam eder. Metot çağrısı yapıldıktan sonra urun adlı değişkenin işaret ettiği nesnenin fiyatı ekrana tekrar yazdırılır.

image

Gördüğümüz gibi, sonuç ilk yaptığımız örnekten farklıdır. urun adlı değişken aynı nesneyi işaret etmektedir. Şimdi de ref anahtar sözcüğü kullanarak aynı örnek üzerinden inceleme yapmaya devam edelim.

class Urun

    {

        public int Id { get; set; }

        public string Ad { get; set; }

        public double Fiyat { get; set; }

 

        public Urun(int id, string ad, double fiyat)

        {

            Id = id;

            Ad = ad;

            Fiyat = fiyat;

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            Urun urun = new Urun(1, "Monitör", 200);

            Console.WriteLine(urun.Fiyat);

 

            Test_urun2_ref(ref urun);

            Console.WriteLine(urun.Fiyat);

 

        }

 

        static void Test_urun2_ref(ref Urun u)

        {

            u = new Urun(2, "laptop", 1500);

            u.Fiyat = 2750;

        }

    }

Main metodu çalışmaya başlar ve ram’e “urun” adında bir değişken çıkar. Daha sonra bu değişkenin işaret ettiği Urun nesnesinin fiyatı ekrana yazdırılır.

image

image

Daha sonra Test_urun2_ref adlı metot çağrılır ve parametre olarak “urun” değişkenin referansı verilir.

image

Metot içerisine girildiğinde heap’e yeni bir Urun nesne örneği çıkar ve adresi “u” işaretçisine atanır.

image

“u” nun işaret ettiği nesnenin fiyatına 2750 değeri atanır. Daha sonra metot sonlanır. “u” değişkeni ile, M60 ve B15 adreslerindeki nesneler sahipsiz kaldığından dolayı ram’den düşerler.

image

Main metodu çalışmaya kaldığı yerden devam eder ve ekrana “urun” değişkeninin işaret ettiği nesnenin fiyatı yazdırılır. Artık işaret edilen nesne adı “laptop” olan üründür. Main metodunun girişinde oluşan nesne ram’den düşmüştür.

image

Gördüğümüz gibi, referans türlü tiplerde ref anahtar sözcüğünün kullanımı farklı sonuçlar doğurabilmektedir.

Faydalı olması dileği ile…