Etiketler

5 Haziran 2014 Perşembe

C# Metotlar - Fonksiyonlar

Herkese merhaba, geçen yazımda sizlere en basit şekliyle sınıfları anlatmıştım. Sınıflar ile ilgili yazımda sınıfımız sadece veri içeriyordu. Artık sınıfların ana bileşeni olan metotları ve metot çeşitlerini inceleyeceğiz. Her zaman olduğu gibi en basit şekliyle elimden geldiğince anlatmaya çalışacağım.

İlk olarak, metot nedir? Yenilir mi içilir mi? gibi akla ilk gelen soruları cevaplayalım. Daha önceki sınıflar ile ilgili yazımda sınıflar c# ın yapı taşıdır demiştim. Ancak sınıfımızla sadece veri çekmiştik ve bu aslında hiç efektif bir kullanım değil. İşte asıl sınıflar metotlar ile birleşince voltranı oluşturuyorlar. İnsanlar programlamayı sürekli "amelelik yapmamak", aynı şeyleri tekrarlamamak, insan hayatını kolaylaştırmak için yazıyor. İşte program yazarken belli bir işi yapmasını istediğimiz bir kod parçası yazdığımız zaman onu tekrar tekrar yazmak yerine sadece bir metot hazırlayıp onu istediğimiz zaman çağırabiliriz. Böylelikle sürekli kod tekrarları yapmamış ve en anlaşılır biçimde kodumuzu şişirmeden efektif biçimde istediğimizi elde etmiş oluruz.Örneğin karekök hesabı yapan bir metot veya faktöriyel hesabı yapan bir metot yazarız ve istediğimiz zaman bu metotları çağırarak istediğimiz sayının karekökünü, faktöriyelini veya istediğimiz herhangi başka bir şeyi yaptırırız.Son olarak, eğer istersek bir metot içerisinde hem faktöriyel hesabı yapan hem karekök hesabı yapan kod parçasını yazabiliriz, ancak her metot'un yalnızca tek bir görevi yapması en iyisidir. Bu yüzden her farklı görev için farklı metotlar oluştururuz. Metotları daha iyi anlamak için için parçala ve yönet stratejisine benzetebiliriz. Yaptırmak istediğimiz şeyleri tek tek metotlara yazıyoruz ve onları istediğimiz zaman çağırıyoruz(yönetiyoruz).

Peki metot nasıl tanımlanır? Genel gösterimi şu şekildedir;

ulaşılabilirlik dönüş-tipi metotismi(varsa-parametreler)
{
       //metodumuzun içi
}

Ulaşılabilirliğe daha önceden sınıflar ile ilgili yazımda kısaca değinmiştim, hani public-private mevzusu.Metotlarda da eğer bu kısmı public yapmazsanız, metot sadece kendi sınıfı içine özel tanımlı olur yani kısaca private olmuş olur.

Dönüş-tipi kısmı metotlarda iyi anlaşılması gereken yerlerden biri olduğunu düşünüyorum. İlk olarak dönüş tipi void olan tipleri inceleyelim.Öncelikle hem metotların amaçlarını iyi kavrayabilmek hemde nasıl tanımlandığını tam kavrayabilmek için basit bir örnekle başlayalım.

    class Program
    {
        static public void dolar()
        {
            Console.WriteLine("Bugun dolar: 2.30TL");
        }

        static void Main()
        {
            Program.dolar();
        }
    }

Öncelikle dönüş tipimizi void olarak atadık. Bunun anlamı "metot ben seni çağırdığım zaman sadece gövdende ki işlemleri yap bana değer falan döndürme" demektir. 

Peki neden direk Main 'in içine Console.WriteLine ile yazdırmadık da metot oluşturup sonra birde onu çağırdık falan, uğraştık böyle? Çünkü şöyle düşünün;  büyük projelerde çalıştığınız zaman 10 kere 20 kere, bir yere doların kurunu yazdıracağız. Ne güzel tek tek oturur yazarız ancak ertesi gün doların kuru değiştiği zaman 20 farklı yerdeki doların değerini tek tek değiştirmeniz gerekecek. Onun yerine direk bir metot tanımlayıp ardından doların değeri değişince direk olarak sadece bir yerdeki değeri değiştirmek bizim işimizi görecek. 

Bir diğer dikkat etmeniz gereken bir nokta ise Program.dolar(); olarak çağırdık metot 'umuzu ancak metot ve main gördüğünüz gibi aynı sınıfın içerisinde yani Program adlı sınıfın içerisinde ikiside.  Hem tanımladığım ve çağıracağım sınıf aynı olduğu için, Program.dolar(); olarak çağırmama gerek yok. Direk dolar(); olarak çağırabilirim.Ancak farklı sınıfta tanımlasaydım metot 'u,  mutlaka sınıfınİsmi.dolar(); gibi çağırmam gerekirdi.

Son olarak burada dikkatinizi çektimi bilmem ancak Main() de gördüğünüz üzere bir metot. Ve buradaki örneğimizde void dönüş tipini kullanıyor. Main 'in diğer metotlardan tek farkı başlatıcı özellikte olmasıdır.
Şimdi yine void ile değer döndürmeyen başka bir örneği inceleyelim.

    class matematik
    {
        static int sayi;

        static public void kareal()
        {
            Console.WriteLine("Karesini istediginiz sayi: ");
            sayi = Convert.ToInt16(Console.ReadLine());
            Console.WriteLine("sayinin karesi: " + sayi * sayi);
        }
    }

    class Program
    {
        static void Main()
        {
            matematik.kareal();
        }
    }

Burada da bir önceki örnekteki gibi void tipinde metot çağırdık. Ancak dikkat etmeniz gereken bazı yerler var. İlk olarak bu örneğimizde iki farklı sınıf kullandığımızı fark etmeniz önemlidir. Bu yüzden main in içinde çağırdığımız kareal(); metodumuzu önünde matematik(yani bulunduğu sınıf) olmadan yazamayız.Bu noktayı gördükten sonra sanırım uzunca süredir kullandığımız Console.WriteLine() 'ın, Convert.ToInt16() 'nın, Console.ReadLine() 'ın aslında bir metot olduğunu ve bunların birer void yani değer döndürmeyen metot olduğunu görmüş olmanız lazım. Yani bu satırlarda diyoruz ki Console sınıfının ReadLine metodunu kullanmak istiyorum bana onu getir. Bunun dışında metot 'un içindeki kodları açıklamıyorum, eğer anlamadıysanız blogumda ki kullanıcıdan girdi almak adlı yazımı okuyabilirsiniz.

Peki şu ünlü return nedir? Yenilir mi içilir mi?

Bu anahtar kelimeyi ilk defa görüyorsanız başlarda birazcık karmaşık gelebilir. Düzgün anlaşılması için çeşitli örnekler yapacağım. Öncelikle kısaca return metot 'un içinde kullanıldığında metodu döndüren bir anahtar kelimemizdir.

        static public void metodumuz()
        {
            if (ProgramBittiyse) return;

            if (Hataliysa) return;
        }

Bu örneğimizde yine dönüş tipi void olan yani değer döndürmeyen bir metot kullandık. Eğer programımız bitti ya da çıkış tuşuna basıldı gibi düşünebiliriz. Ardından return 'e gidiyor. Ve return hemen metodumuzu döndürüyor. void hatırlayacağınız üzere değer döndürmeyen bir tip olduğu için program orda öylece kalıyor. Yani dönüş tipi void olan bir metot da return kullandıktan sonra bir işlem yapamyız. En basitinden Console.WriteLine() ile ekrana herhangi bir şey yazdıramayız. Bunu kendiniz de yazıp test edebilirsiniz.

Daha iyi anlayabilmek için farklı bir örnekle daha dönüş tipi void olan bir metot da return kullanalım.

        static public void metodumuz()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
                if (i == 4)
                {
                    return;
                }
            }
        }

Buradaki örneğimizde for döngüsü ile ekrana 0 dan başlayarak 9 dahil, rakamları yazdırmak istedik. Ancak programı derledik ve o da nesi? 4 'e kadar olan rakamları yazmış ancak devamı yok. Çünkü programımız 4 e geldiğinde return ile dönmesini istedik. Ve dönüş tipimiz void (yani dönmeyen tip) olduğu için programımız orada duruyor. 
Şimdi void dönüş tipi dışındaki diğer dönüş tiplerini ve return 'ü kullandığımızda nasıl olduğunu anlamak için yine basit bir örnekle başlayalım.

    class Program
    {
        static int donustipitamsayi()
        {
            int sayi = 5;
            return sayi;
        }

        static void Main()
        {
            Console.WriteLine(donustipitamsayi());
        }
    }

Bu örneğimizde dikkat ettiyseniz dönüş tipi yerine void değil int kullandık. Bu demek oluyor ki; beni döndürdüğün(return kullandığın) zaman sana tam sayı(integer) tipinde döndüreceğim değeri. Metodumuzun gövdesine bakarsak sayi değişkenimizi tam sayı olarak 5 değerine eşitledik. Ardından sayi değişkenimizi döndürdük. Bunu yapınca ne oldu? donustipitamsayi() adlı metodumuz 5 değerini tam sayı(int) tipinde döndürmüş oldu. Bu yüzden metodumuzu ekrana yazdırdığımız zaman ekrana 5 yazdırdı. 
Dikkat etmeniz gereken nokta metodumuzun sadece int tipinde değer döndürdüğüdür ve biz int tipinden farklı bir tip kullanırsak(dikkat: short tipi kullanarak int döndürebiliriz) derleyicimiz hata verecektir. Örneğin şöyle bir şey yapamayız;

        static int donustipitamsayi()
        {
            string sayi = "abc";
            return sayi;

        }

Yukarıdaki gibi bir şey yapmaya kalkarsak derleyici bize "ne yapıyorsun kardeş ben string den int e dönüş yapamam" diyecektir.

Şimdi hem sınıfları kullandığımız hemde int tipinde değer döndürdüğümüz metot kullanarak bir örnek yapalım.

    class Kayit
    {
        public int yas;
        public int boy;

        public int oran() //metodumuz
        {
            return boy / yas;
        }
    }

    class Program
    {
        static void Main()
        {
            Kayit ogrenci1 = new Kayit();
            Kayit ogrenci2 = new Kayit();

            //ilk öğrenci için
            ogrenci1.yas = 17;
            ogrenci1.boy = 170;

            //ikinci öğrenci
            ogrenci2.yas = 18;
            ogrenci2.boy = 180;

            //oranı hesaplayalım
            int index1 = ogrenci1.oran();
            int index2 = ogrenci2.oran();

            Console.WriteLine("Birinci ogrencimizin indexi: " + index1); // 170 / 17
            Console.WriteLine("İkinci  ogrencimizin indexi: " + index2); // 180 / 18
        }
    }

Sınıflara daha önceki yazımda anlatmıştım, o yüzden sadece int tipindeki metodumuza bakalım. Öncelikle oran() adlı metodumuz iki farklı değişkenin bölümünü döndürüyor burada. Ancak dikkat edin değişkenlerimizin hepsi int tipinde ve metot 'umuzda int tipinde. 
Bunları yine int tipindeki index1 ve index2 değişkenlerimizi kullanarak return edilen ifadeyi bu değişkenlerimizin içine alıyoruz. Ve ekrana yazdırıp istediğimiz sonucu alıyoruz.

Son olarak metotlarda parametre kullanımından bahsetmek istiyorum. Hemen bunu güzel bir örnekle açıklayalım. Bu örneğimizde 0 dan 9 a kadar olan asal sayıları bulup sonrasında bu asal sayıların karesini alacağız.


    class Kontrol
    {
        public bool asalmi(int a)
        {
            for (int i = 2; i < a - 1; i++)
            {
                if (a % i == 0) return false;
            }

            return true;
        }
    }


    class Program
    {
        static void Main()
        {
            Kontrol nesnemiz = new Kontrol();;

            for (int sayi = 0; sayi < 9; sayi++)
            {
                if (nesnemiz.asalmi(sayi))
                {
                    Console.WriteLine(sayi* sayi); // asal sayinin karesini al
                }
            }
        }
    }

Daha önceki bir yazımda zaten detaylıca C# da Asal Sayı Bulma olayını anlatmıştım, bu yüzden o kısımlara değinmeyeceğim. İlk olarak asalmi adında bir metodumuz var, dikkat edin bunun diğerlerinden farkı bir parametre alabilir olmasıdır. Yani yanındaki parantezlerde int a yazıyor. İşte biz bu metodumuzu çağırdığımız zaman aynı zamanda bir parametre değeri de girmemiz gerekiyor. İşte biz bu parametreyi if (nesnemiz.asalmi(sayi))kısmında giriyoruz.
Eğer sayi değerimiz bir asal sayıysa, metodumuz true olarak dönüyor. Eğer asal sayı değilse metodumuz false olarak dönüyor. 
Neden if (nesnemiz.asalmi(sayi)) gibi bir satır yazdığımızıda anlamışsınıdır sanırım. Eğer asal ise true dönüyor ve bildiğiniz üzre if(true) olursa derleyicimiz if ifadesinin içine giriyor. Ve ardından asal sayının karesini almak için bulduğu sayıyla kendisini çarpıp ekrana yazdırıyor.