27 Şubat 2023 Pazartesi

C# Temelleri 4

  Merhaba direk bu sayfaya gelenler için belirteyim, bu yazı serinin dördüncü yazısı. Önceki bölümler için 

https://ujk-ujk.blogspot.com/2023/01/c-temelleri-1.html ve 

https://ujk-ujk.blogspot.com/2023/02/c-temelleri-2.html ve

https://ujk-ujk.blogspot.com/2023/02/c-temelleri-3.html

sayfalarına bakınız.


En son artık ağır konulara gireceğimizi belirtmiştik, hadi başlayalım.


C# Sınıf Tanımları (class)

Sınıflar bir konu ya da bir şeyle ilgili kodlarımızı bir arada topladığımız bloklardır. Daha önce hazır sınıf örnekleri kullandık. Mesela Console sınıfı içinde tanımlanmış ReadLine(), WriteLine() gibi metodları kullandık. Math sınıfı içinde tanımlanmış Pow(), Sqrt() gibi metodları kullandık. String sınıfının Length özelliğini kullandık vs. 

Sınıflar içinde bir nesne üretmek ve kullanmak için gereken kodlar bir araya toplanır. Mesela bir String değişken oluşturduğumuzda aslında String sınıfı yapısına sahip bir nesne (object) oluşturuyoruz. Daha sonra oluşturduğumuz bu değişken üzerinde String sınıfının metodlarını uyguluyor ve özelliklerini kullanıyoruz. C# ve benzeyen bir çok programlama dili böyle sınıf yapıları üzerine kurulmuştur ve bu sınıflardan üretilen nesneler kullanılarak program yazarız. Bu şekil programlamaya nesne tabanlı programlama (object oriented programming - OOP) denir. 

Programlarımızı içine yazdığımız Main() metodu da Program sınıfı içinde tanımlanmıştır.

    class Program
    {
        static void Main(string[] args)
        {
           

            Console.ReadKey();
        }
    }

Biz de kendi sınıflarımızı tanımlayıp onlardan ürettiğimiz nesneleri kullanabiliriz ya da bu sınıflar içinde metodlar tanımlayıp kullanabiliriz. Sınıf tanımlarken aynı bulunduğumuz dosya içerisinde Program sınıfına benzer şekilde ama dışında arkasına ekleyerek tanımlayabileceğimiz gibi, tamamen ayrı bir dosya içinde kendi sınıfımızı tanımlayabiliriz. Burada ayrı dosya olup olmaması için en çok bakılan kriter programın uzunluğudur, programınız çok uzun oluyorsa ayrı dosyada sınıf tanımı yaparsınız. Her iki yöntemi de göreceğiz. 

Örnek olarak yararlı olacağını düşündüğümüz bazı mesajları veren metodları içeren bir sınıf tanımlaması yapalım.

    class Program
    {
        static void Main(string[] args)
        {
           

            Console.ReadKey();
        }
    }
    class Mesajlar
    {
        void Merhaba()
        {
            Console.WriteLine("Merhaba, programımıza hoş geldiniz");
        }
        void Bekle()
        {
            Console.WriteLine("Bir şeyler bekliyorum");
        }
        void Hoşçakal()
        {
            Console.WriteLine("Hoşçakalın, ziyaretiniz için teşekkürler");
        }
    }

Bu metodları kullanmadan önce yapıya bir bakalım, aynı yukarıda hazır bulduğumuz Program sınıfı gibi bir tanımlama yaptık ve içine metod tanımlamalarımızı koyduk. Peki bunları ayrı bir dosya içinde tanımlamak istersek?

Visual Studio editörde sağ üst köşede Çözüm Gezgini vardı (Solution Explorer) burada proje adımızın üzerine sağ tıklayıp Ekle ve Sınıf seçelim.

İngilizce olursa Add ve class.. tıklanır. Karşımıza projeye bileşen eklemek için bir pencere çıkar. Burada dosya adı olarak mesela Mesajlar girelim.

Ekle butonunu tıkladığımızda çözüm gezgininde yeni bir dosya eklendiğini görürüz. Adı Mesajlar.cs ve dosya editörde otomatik olarak açılır.

Mesajlar.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpTemelleri
{
    class Mesajlar
    {
    }
}

Dikkatimizi Mesajlar yazısı altındaki kırmızı uyarı çizgisi çeker. Kursörü üzerine götürürsek zaten CSharpTemelleri isim alanı içinde Mesajlar diye bir sınıf tanımı var diyecektir. Bu daha önce aynı dosya içinde yaptığımız sınıf tanımı ile çakıştığını anlatıyor. Şimdi orada tanımladığımız metodları buraya kopyalayalım ve Program.cs dosyası içindeki sınıf tanımını silelim.

Program.cs
using System;

namespace CSharpTemelleri
{
    class Program
    {
        static void Main(string[] args)
        {
           

            Console.ReadKey();
        }
    }
}

Mesajlar.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpTemelleri
{
    class Mesajlar
    {
        void Merhaba()
        {
            Console.WriteLine("Merhaba, programımıza hoş geldiniz");
        }
        void Bekle()
        {
            Console.WriteLine("Bir şeyler bekliyorum");
        }
        void Hoşçakal()
        {
            Console.WriteLine("Hoşçakalın, ziyaretiniz için teşekkürler");
        }
    }
}


Gelelim bu yazdığımız metodları nasıl kullanacağımıza. İki değişik yöntem kullandık daha önce hiç farketmeden. Bir tanesi sınıftan bir nesne üretmek ve o nesnenin metodlarını kullanmaktı. Random sayı meselesini hatırlarsak.

            Random random = new Random();
            random.Next();

Örneğinde olduğu gibi. Biz de deneyelim,

Ops! Bir sorun var. Bizim tanımladığımız metodlar yardım listesine gelmedi. Metodlarımızın dışarıdan erişilebilir olması için metod tanımları başına public (genel kullanıma açık) kelimesi eklememiz gerekiyor, yoksa metodlar sınıf tanımı içinde kullanılan yardımcı metodlar gibi kabul görür ve dışarıdan erişilemez. Mesajlar.cs dosyamıza geri dönelim ve metod tanımlarının başına public kelimelerini ekleyelim.

Mesajlar.cs
    class Mesajlar
    {
        public void Merhaba()
        {
            Console.WriteLine("Merhaba, programımıza hoş geldiniz");
        }
        public void Bekle()
        {
            Console.WriteLine("Bir şeyler bekliyorum");
        }
        public void Hoşçakal()
        {
            Console.WriteLine("Hoşçakalın, ziyaretiniz için teşekkürler");
        }
    }

Artık metodlarımızı kullanabiliriz.

Program.cs
        static void Main(string[] args)
        {
            Mesajlar mesajlar = new Mesajlar();
            mesajlar.Merhaba();
            mesajlar.Bekle();
            mesajlar.Hoşçakal();

            Console.ReadKey();
        }

Metodları kullanmamızın ikinci yolu ise daha önce Math sınıfı metodlarında gördüğümüz gibi yeni nesne üretmeden direk kullanmaktır. Örnek

            Console.WriteLine(Math.Sqrt(2));

Metodlarımızı bu şekilde kullanmayı deneyelim.

Yine olmadı. Metodlarımızı yeni nesne üretmeden direk kullanabilmek için de hem sınıf tanımının başına hem de kullanmak istediğimiz metodların başına static kelimesi eklememiz gerekiyor. İlerde daha ayrıntılı göreceğiz , şimdilik sadece kelimeyi koyalım.

Mesajlar.cs
    static class Mesajlar
    {
        public static void Merhaba()
        {
            Console.WriteLine("Merhaba, programımıza hoş geldiniz");
        }
        public static void Bekle()
        {
            Console.WriteLine("Bir şeyler bekliyorum");
        }
        static public void Hoşçakal()
        {
            Console.WriteLine("Hoşçakalın, ziyaretiniz için teşekkürler");
        }
    }

Bakarsak sıralamada Hoşçakal() metodu tanımında değişik yazdım , o da kabul ama teamül public static şeklinde yazılmasıdır. void kelimesinin yerini zaten değiştiremeyiz o metoddan ne tip veri döneceğini belirtiyor. Şimdi metodlarımızı kullanalım.

Program.cs
        static void Main(string[] args)
        {
            Mesajlar.Merhaba();
            Mesajlar.Bekle();
            Mesajlar.Hoşçakal();

            Console.ReadKey();
        }

Çalıştıralım

Harika!. Peki şimdi önceden yaptığımız sınıftan bir nesne üreterek metodlarını kullanma yöntemi çalışır mı? Çalışmaz çünkü static olarak tanımlaması yapılan bir sınıftan nesne üretilmesine izin verilmez. İhtiyacımıza göre birini seçeceğiz. Bir konuda bize yardımcı olacak metodları toplayacağımız bir sınıf tanımı yapıyorsak static olarak tanımlarız. Ama bir nesne üretecek ve o nesnenin özelliklerini ve metodlarını kullanacaksak static olmayan sınıf tanımlaması yaparız. Örnekler yaptıkça göreceğiz. 




C# Nesneler (Objects)

Konular karmaşıklaşmaya başladı. Ancak daha önce gördüğümüz ama ne olduğunu nasıl yapıldığını bilmediğimiz şeyleri öğrenmek de heyecan verici. Bir nesne demek programlamada bir sınıf tanımından üretilmiş nesne demektir. Bu nesnelere sınıfın oluşumu denir, bundan sonra çok kullanacağımız bir kavram. Nesneleri oluşturmak için sınıf tanımlamalarını kullanırız. Bu yapı aslında gerçek dünyadan esinlenmiş bir yapıdır. Etrafımızda bir çok nesneler var bilgisayar, koltuk, masa, televizyon vs. 

Gerçek hayattan nesneleri kodumuzda da nesneler olarak ifade edebiliriz. Nesnelerin özellikleri vardır ve eylemleri vardır. Örneğin İnsan sınıfı tanımından kişiler oluşturabiliriz. Bu amaçla ilk önce bir sınıf tanımı yapmamız gerekiyor. 

namespace CSharpTemelleri
{
    class Program
    {
        static void Main(string[] args)
        {
           

            Console.ReadKey();
        }
    }
    class İnsan
    {

    }
}

Fazla karmaşık işler yapmayacağımız için sınıf tanımımızı ayrı bir dosyada yapmaya gerek yok. Aynı dosya içinde Program sınıfı tanımı dışında ama CSharpTemelleri isim alanımız içinde İnsan sınıfını tanımlamaya başlayalım. 

Demiştik ki nesnelerin özellikleri olur. Diyelim İnsan sınıfından üreteceğimiz kişi nesnelerinin isim ve yaş özellikleri olsun. 

    class İnsan
    {
        String isim;
        int yaş;
    }

Tanımladık ama şimdilik bir değer vermedik. Bunlar üreteceğimiz nesnelerin özellikleri. Eylemler ise metodlardır. Bir İnsan oluşumu ne eylemlerde bulunabilir? (ya da bizim programımızda kullanmayı düşündüğümüz İnsan oluşumlarında biz hangi eylemleri yapmak istiyoruz?). Örnek olarak yemek yediği ve uyuduğunu düşünelim ve bunlar için de sınıf tanımımıza metodlar ekleyelim.

    class İnsan
    {
        String isim;
        int yaş;

        void YemekYer()
        {
            Console.WriteLine(isim + " yemek yiyor.");
        }
        void Uyur()
        {
            Console.WriteLine(isim + " uyuyor.");
        }
    }

Kullanmaya başlayalım. Programımız içinde bir kişi nesnesi üretelim.

        static void Main(string[] args)
        {
            İnsan kişi1 = new İnsan();

            Console.ReadKey();
        }

Fakat yine unuttuk, kişi1 nesnesinin özellikleri ve metodlarına erişemiyoruz. Erişmek için başlarına public kelimesi koymalıyız. 

    class İnsan
    {
        public String isim;
        public int yaş;

        public void YemekYer()
        {
            Console.WriteLine(isim + " yemek yiyor.");
        }
        public void Uyur()
        {
            Console.WriteLine(isim + " uyuyor.");
        }
    }

Şimdi kişi1 nesnemizin özelliklerine değer verip eylemlerini kullanabiliriz. 

            İnsan kişi1 = new İnsan();

            kişi1.isim = "Hasan";
            kişi1.yaş = 38;
            kişi1.YemekYer();

İnsan sınıfı tanımını bir kere yaptık ama kişi nesnelerinden istediğimiz kadar oluşturabiliriz. İkinci bir kişi oluşturalım. 

            İnsan kişi2 = new İnsan();

            kişi2.isim = "Dilek";
            kişi2.yaş = 42;
            kişi2.Uyur();

ve çalıştıralım

Bunlar nesneler için ön bilgiler daha öğreneceğimiz çok şey var.




C# Nesne İnşa Ediciler (constructor)

Bir sınıftan bir nesne oluşumu üretirken girilmesi gerektiğini düşündüğümüz değerler girilerek üretilmesini sağlamak amacıyla constructor adı verilen inşa edici metodlar kullanılır. Bunlar sınıfın üretici metodlarıdır ve bu metod isimleri sınıf adı ile aynı olmalıdır. 

Bir önceki örneğimizi düşünürsek önce kişi nesnelerini ürettik daha sonra isim ve yaş özelliklerine ayrı satırlarda değerler girdik. Bu değerler girilerek kişi nesnesinin üretilmesini istersek sınıfa üretici metod ekleriz, şöyle ki,

    class İnsan
    {
        public String isim;
        public int yaş;

        public İnsan(String isim, int yaş)
        {

        }
        public void YemekYer()
        {
            Console.WriteLine(isim + " yemek yiyor.");
        }
        public void Uyur()
        {
            Console.WriteLine(isim + " uyuyor.");
        }
    }

Artık yeni kişi üretirken değerler girmek zorundayız.

        static void Main(string[] args)
        {
            İnsan kişi1 = new İnsan("Hasan", 38);
            İnsan kişi2 = new İnsan("Dilek", 42);

            kişi1.YemekYer();
            kişi2.Uyur();

            Console.ReadKey();
        }

Bununla beraber, programı çalıştırırsak kişi nesnelerimizin özelliklerinin otomatik olarak verilmediğini görürüz. 

Eğri oturup doğruyu konuşalım, programlama dilleri şu anda kafamızdan geçenleri anlayacak kadar zeki değiller. Biz orada sınıfın üretici metodunu tanımlarken isim diye bir String parametre var dedik diye "aaa benin sınıf tanımımda da aynı isimde özellik var demek ki yazılımcı bunu demek istiyor" diye çalışmazlar. Kurallar vardır , her şeyi açık ve net belirtmeliyiz.

Gönderilen parametre değerlerini özelliklere atamak için üretici metodumuz içine şunları yazalım.

        public İnsan(String isim, int yaş)
        {
            this.isim = isim;
            this.yaş = yaş;
        }

Şimdi program doğru çalışacaktır. this.isim demek , bu üretici metod yeni nesne üretirken çalışacağından , o anda üretilen nesnenin isim özelliği demektir. Metoda parametre adı olarak farklı şeyler de verebiliriz, burada amaç sürekli değişik kelimeler bulmaya çalışmamak, ama ilk başlayanlarda çok kafa karıştırdığı da olur. Mesela,

        public İnsan(String isimP, int yaşP)
        {
            this.isim = isimP;
            this.yaş = yaşP;
        }

şeklinde yazsak tabi ki yine çalışır ve biz de "ya işte parametre isim için isimP yazarak sınıf özelliğiisimden ayırdık" diyebiliriz. Bir şey daha belirteyim,

        public İnsan(String isimP, int yaşP)
        {
            isim = isimP;
            yaş = yaşP;
        }

şeklinde yazabiliriz artık. Çünkü derleyici için tek bir isim tanımı kaldı ve this.isim dememize gerek kalmaz. 

        public İnsan(String isim, int yaş)
        {
            isim = isim;
            yaş = yaş;
        }

ama bu çalışmaz, derleyici hangi isim değişkeni kullanacağına şöyle karar verir, önce varsa metod parametresindeki isim değeri, sonra dışarı bakar. Parametrede de isim değeri olduğuna göre onu alır ve aynı değeri aynı yere atamak olarak algılar. Zaten bu konuyu da editörümüz bize uyarır.

Uzun lafın kısası "biz işimizi kış tutalım, yaz çıkarsa bahtımıza" deyip this.isim notasyonunu kullanalım. 

Daha gelişmiş bir örnek için bir Araç nesnesi düşünelim. 4 özelliği olsun, markası, modeli, yılı ve rengi. 

    class Araç
    {
        String marka;
        String model;
        int yıl;
        String renk;
    }

Sınıf tanımına bir üretici metod ekleyelim ve bir de eylem ekleyelim.

    class Araç
    {
        String marka;
        String model;
        int yıl;
        String renk;

        public Araç(String marka, String model, int yıl, String renk)
        {
            this.marka = marka;
            this.model = model;
            this.yıl = yıl;
            this.renk = renk;
        }
        public void Kullan()
        {
            Console.WriteLine($"{marka} marka, {model} model, {renk} renk bir araç");
        }
    }

Şimdi Araç sınıfımızın bir oluşumunu üretelim ve kullanalım.

        static void Main(string[] args)
        {
            Araç araç1 = new Araç("Ford", "Mustang", 2022, "Kırmızı");

            araç1.Kullan();

            Console.ReadKey();
        }

ve sonuç,

İkinci bir araç nesnesi üretelim,

        static void Main(string[] args)
        {
            Araç araç1 = new Araç("Ford", "Mustang", 2022, "Kırmızı");
            Araç araç2 = new Araç("Chevy", "Corvette", 2021, "Mavi");

            araç1.Kullan();
            araç2.Kullan();

            Console.ReadKey();
        }

Üretici metodlar hakkında daha söylenecekler var ama biraz ilerdeki konularda göreceğiz.




C# static Kelimesi

static kelimesini daha önceden hatırlıyoruz. Mesela sınıf metodlarına nesne üretmeden direk erişmek için sınıfı ve metod tanımlarının başına static kelimesi eklememiz gerekiyordu. Şimdi static kelimesinin başka bir kullanımını göreceğiz. 

static kelimesi sınıftan üretilen nesnelere değil de sınıfın kendisine bağlı özellikleri tanımlamak için de kullanılır. Örnek olarak basit bir Araç sınıfı tanımı ve kullanımı ile başlayalım.

    class Program
    {
        static void Main(string[] args)
        {
            Araç araç1 = new Araç("Mustang");
            Araç araç2 = new Araç("Corvette");

            Console.ReadKey();
        }
    }
    class Araç
    {
        String model;

        public Araç(String model)
        {
            this.model = model;
        }
    }

Farz edelim toplam kaç tane araç oluşumu ürettiğimizi bilmek istiyoruz. Bu durumda sınıf tanımı içinde bir yerde kaç tane oluşum nesnesi üretildiğini kaydetmemiz gerekiyor. Bunu static tanımlı özellik kullanarak yapabiliriz. Öncelikle static olmayan bir özelliğe toplam araç sayısını kaydetmeye kalkarsak ne olur görelim.

    class Araç
    {
        String model;
        public int araçSayısı;

        public Araç(String model)
        {
            this.model = model;
            araçSayısı++;
        }
    }

Dışarıdan erişebilmek için public tanımlanmış bir araçSayısı değişken değerini her yeni araç nesnesi üretildiğinde bir arttırıyoruz. Ana kodumuzda yaptığımızı test edelim,

        static void Main(string[] args)
        {
            Araç araç1 = new Araç("Mustang");
            Araç araç2 = new Araç("Corvette");

            Console.WriteLine(araç1.araçSayısı);
            Console.WriteLine(araç2.araçSayısı);

            Console.ReadKey();
        }

çalıştırıp kontrol ettiğimizde,

2 olamamış, çünkü araçSayısı değişkeni üretilen nesnenin bir özelliğidir ve her yeni araç nesnesi üretildiğinde değer sıfırdan başlıyor. Özellik değerinin nesneye değil sınıfa bağlı olması için static olarak belirtmeliyiz.

    class Araç
    {
        String model;
        public static int araçSayısı;
...

ve artık nesnenin değil sınıfın bir özelliği olduğu için erişim şeklimizi de değiştirmeliyiz.

            Araç araç1 = new Araç("Mustang");
            Araç araç2 = new Araç("Corvette");

            Console.WriteLine(Araç.araçSayısı);

Zaten araç1.araçSayısı yazsak da çalışmayacak ve bize araçSayısı özelliğine sınıf adı ile erişebileceğimizi bildirecektir. 

Daha önce hatırlarsak sınıf tanımlarında sınıfı static olarak tanımladığımızda o sınıftan artık bir nesne üretilemediğini gördük. Ancak buradaki gibi sınıf tanımı static değilken özellikleri ve metodları içinde istediğimizi static yapabiliyoruz. Örnek olarak bir de static metod tanımı yapalım. 

        public static void YarışBaşlasın()
        {
            Console.WriteLine("Yarış " + araçSayısı + " araç ile başladı!");
        }

ve ana kodumuzda bu metodu direk olarak kullanalım.

            Araç araç1 = new Araç("Mustang");
            Araç araç2 = new Araç("Corvette");
            Araç araç3 = new Araç("Lambo");

            Araç.YarışBaşlasın();

ve sonuç

Gördüğümüz gibi static olarak nitelendirilen özellik ve metodlar direk olarak sınıfa bağlanıyor ve nesne oluşumlarından bağımsız kullanılıyor. 




C# Üretici Metodların Tekrarlanması (overloading constructors)

Daha önce metodların tanımlanmasında gördüğümüz gibi sınıf üretici metodları da tekrar tanımlamalar ile nesne üretiminde değişik yöntemler kullanabilirler. Örnek olarak pizza yapımını düşünelim.

    class Pizza
    {
        String hamur;
        String sos;
        String peynir;
        String malzeme;

        public Pizza(String hamur, String sos, String peynir, String malzeme)
        {
            this.hamur = hamur;
            this.sos = sos;
            this.peynir = peynir;
            this.malzeme = malzeme;
        }
    }

Şimdi ana programda bir pizza nesnesi üretelim.

        static void Main(string[] args)
        {
            Pizza pizza = new Pizza("kalın kenar", "salça sos", "mozarella", "sucuk");

            Console.ReadKey();
        }

Ama diyelim biz üzerinde malzeme olmayan pizza yapmak istersek, o opsiyonu boş bırakamayız. Değer olarak "yok" ya da boş string girebiliriz ama biz burada örnek vermeye çalışıyoruz. malzeme değeri girilmeden de pizza nesnesi üretebilmek için üretici metoda ikinci bir tanım yaparız. 

    class Pizza
    {
        String hamur;
        String sos;
        String peynir;
        String malzeme;

        public Pizza(String hamur)
        {
            this.hamur = hamur;
        }
        public Pizza(String hamur, String sos)
        {
            this.hamur = hamur;
            this.sos = sos;
        }
        public Pizza(String hamur, String sos, String peynir)
        {
            this.hamur = hamur;
            this.sos = sos;
            this.peynir = peynir;
        }
        public Pizza(String hamur, String sos, String peynir, String malzeme)
        {
            this.hamur = hamur;
            this.sos = sos;
            this.peynir = peynir;
            this.malzeme = malzeme;
        }
    }

Yapmışken bir kaç olasılık ekledik. Artık malzeme olmadan da pizza nesnesi oluşturabiliriz.

        static void Main(string[] args)
        {
            Pizza pizza = new Pizza("kalın kenar", "salça sos", "mozarella");

            Console.ReadKey();
        }

Aklıma gelmişken burada bir kısaltma yapabiliriz. Derleyici Pizza sınıfından bir nesne üretmek istediğimizi bildiği için 

        static void Main(string[] args)
        {
            Pizza pizza = new("kalın kenar", "salça sos", "mozarella");

            Console.ReadKey();
        }

şeklinde bir tanımlamayı da kabul edecektir. Gözünüze nasıl güzel geliyorsa onu kullanabilirsiniz. 




C# Kalıtım Yoluyla Sınıf Tanımlama (inheritance)

Bir ana sınıfın özellikleri ve eylemlerini de kullanabilen ama kendine özgü özellik ve eylemleri olan sınıf tanımlamalarında kalıtım yöntemi (inheritance) ile ana sınıftan alt sınıflar üretiriz. Örnek olarak bir Araç sınıfını ana sınıf olarak tanımlayalım.

    class Araç
    {
        public int hız = 0;

        public void Git()
        {
            Console.WriteLine("Bu araç gidiyor");
        }
    }

Her araç farklı özelliklere sahip olacakken eğer Araç sınıfından kalıtım yoluyla tanımlanırsa Araç sınıfının hız özelliği ve Git() eylemini ortak kullanırlar. Örnek olarak Araç sınıfından Otomobil, Bisiklet ve Tekne sınıflarını kalıtım yoluyla tanımlayalım. 

    class Araç
    {
        public int hız = 0;

        public void Git()
        {
            Console.WriteLine("Bu araç gidiyor");
        }
    }
    class Otomobil : Araç
    {
        public int tekerSayısı = 4;
    }
    class Bisiklet : Araç
    {
        public int tekerSayısı = 2;
    }
    class Tekne : Araç
    {
        public int tekerSayısı = 0;
    }

Alt sınıfı tanımlarken ana sınıfın adını iki nokta üst üste işaretinden sonra ekliyoruz. Bu durumda 3 sınıf kalıtım yoluyla Araç sınıfından tanımlanmış olur ve Araç sınıfına ait hız özelliği ve Git() eylemi bu 3 alt sınıf için de geçerlidir. Şimdi bu sınıfların oluşum nesnelerini üretip test edelim. 

        static void Main(string[] args)
        {
            Otomobil otomobil = new Otomobil();
            Bisiklet bisiklet = new Bisiklet();
            Tekne tekne = new Tekne();

            Console.WriteLine(otomobil.hız);
            Console.WriteLine(otomobil.tekerSayısı);
            otomobil.Git();

            Console.ReadKey();
        }

Gördüğümüz gibi Araç ana sınıfına ait olan hız özelliği ve Git() eylemini otomobil nesnesi için de kullanabiliyoruz. Çalıştırırsak,

Örnek küçük tutulduğu için pek anlaşılmayabilir ama bir aracın sahip olabileceği yüzlerce özellik ve eylemi düşünürsek bunları tanımladıktan sonra bir otomobil ya da bisiklet için ortak olan bir çok şeyi tekrar tanımlama zahmeti ve karışıklığından kurtulmuş oluyoruz. 





C# Soyut Sınıf Tanımları (Abstract Classes)

Soyut sınıf tanımları çoğunlukla ana sınıflar için kullanılır. Bahsi geçen sınıfın tanımının tam olarak bitmediği ve eksikleri olduğu için nesne oluşumunda kullanılamayacağını ifade etmek için kullanılır. Bir önceki Araç ana sınıfının değişik bir uygulamasını yapalım.

    class Araç
    {
        public int hız = 0;

        public void Git()
        {
            Console.WriteLine("Bu araç gidiyor");
        }
    }
    class Otomobil : Araç
    {
        public int tekerSayısı = 4;
        public int maxHız = 180;
    }
    class Bisiklet : Araç
    {
        public int tekerSayısı = 2;
        public int maxHız = 80;
    }
    class Tekne : Araç
    {
        public int tekerSayısı = 0;
        public int maxHız = 60;
    }

Şu andaki haliyle biz Araç ana sınıfından da bir nesne oluşturabiliriz.

        static void Main(string[] args)
        {
            Otomobil otomobil = new Otomobil();
            Bisiklet bisiklet = new Bisiklet();
            Tekne tekne = new Tekne();
            Araç araç = new Araç();

            Console.ReadKey();
        }

Ama biliyoruz ki, Araç sınıfının eksik özellikleri var kaç tekerleği olduğunu ve maksimum hangi hızda gidebileceğini belirleyemiyoruz. Mesela programımızda bu araçları yarıştıracaksak bu eksik özellikleri yüzünden Araç sınıfından bir nesne oluşturulmasını istemeyiz. Bunu sisteme bildirmek için sınıf tanımı başına abstract kelimesini ekleriz. 

    abstract class Araç
    {
        public int hız = 0;

        public void Git()
        {
            Console.WriteLine("Bu araç gidiyor");
        }
    }

abstract kelimesini Araç sınıfı tanımının başına eklediğimiz anda yukarıdaki kodda araç nesnesi üretilirken bir hata bildirimi gelecektir.

Diyor ki bu soyut bir sınıf ve bundan bir nesne oluşumu yapamazsın. Bu sayede kendimizi ve bizden başka aynı proje üzerinde çalışan yazılımcıları yanlış nesne üretmekten korumuş oluruz. Basit bir güvenlik önlemi. 





C# Nesnelerden Oluşan Array

Daha önce array yapısını gördük, şimdi de nesnelerden oluşan bir array oluşturulması ve kullanımına bakalım. 

    class Araç
    {
        public String model;

        public Araç(String model)
        {
            this.model = model;
        }
    }

Araç sınıfından birkaç nesne oluşturalım,

        static void Main(string[] args)
        {
            Araç araç1 = new Araç("Mustang");
            Araç araç2 = new Araç("Corvette");
            Araç araç3 = new Araç("Lambo");

            Console.ReadKey();
        }

Bu araçları bir array içinde yerleştirmek istersek daha önce nasıl String değerlerden oluşan array tanımlarken String[] kullandıysak Araç değerlerden oluşan bir array tanımlamak için de Araç[] kullanırız.

            Araç[] garaj = new Araç[3];
            Araç araç1 = new Araç("Mustang");
            Araç araç2 = new Araç("Corvette");
            Araç araç3 = new Araç("Lambo");

            garaj[0] = araç1;
            garaj[1] = araç2;
            garaj[2] = araç3;

Şimdi konsolda bir gösterimini yapalım,

            Console.WriteLine(garaj[0]);

Bu bize garaj[0] array elemanının veri tipini yazacaktır.

Nesnenin model özelliğini yazdırmak istersek,

            Console.WriteLine(garaj[0].model);

Şeklinde yazarız. Hepsini bir foreach döngüsü ile yazmak istersek,

            foreach (Araç araç in garaj)
            {
                Console.WriteLine(araç.model);
            }

Array tanımlamasını direk değer girerek yapmak istersek nesne oluşumlarını array elemanları olarak gireriz. 

            Araç[] garaj = { new Araç("Mustang"), new Araç("Corvette"),
new Araç("Lambo") };

            foreach (Araç araç in garaj)
            {
                Console.WriteLine(araç.model);
            }


Bu yazı da fazla uzadı editör teklemeye başladı bu kadarı ile yayınlayalım sonra devam edeceğiz. Kalın sağlıcakla..

Sonraki bölüm https://ujk-ujk.blogspot.com/2023/03/c-temelleri-5.html








Hiç yorum yok:

Yorum Gönder