İlk derslerimizden itibaren hazırladığımız konsol uygulamaları ile C# temel yapılarını inceliyoruz. Bu dersimizde daha önce değinme fırsatı bulamadığımız fonksiyon, sınıf ve obje yapılarını inceleyerek eğitimimizin C# temellerine dair bölümünü tamamlayacağız. Önümüzdeki eğitimler içerisinde Visual Studio altında Windows Forms uygulamaları geliştirerek her ay farklı bir alanda uygulama geliştirme fırsatı yakalayacağız ve siyah komut satırı ekranına veda edeceğiz.

Veri yönetim biçimleri her programlama dilinde farklıdır. Nesne tabanlı programlama dillerinde ise çalışma sırasında bütün veriler nesnelere dönüşür ve referans ya da doğrudan bağlantıyla program akışı içerisinde kullanılırlar. C# altında da bütün veri tipleri ikiye ayrılır: temel tipteki nesneler ve sınıf referansı nesneleri. Temel tipteki nesneler önceki örneklerimizde bolca kullandığımız, byte, sayı, karakter veya metin değeri alan int, char veya string gibi C# içerisindeki dahili tiplerdir. Diğer veri tipleri ise bizim yazdığımız sınıflar (class) kullanılarak üretilen nesnelerdir.. Sınıflar nesne yönelimli programlamanın çekirdeğini oluşturan en küçük yapılar olarak projenizin sürdürülebilirliği, geliştirilebilir ve güvenliğine katkıda bulunur.

Ancak sınıf yapısına geçmeden önce, sınıfları oluşturan diğer bir önemli unsur olan fonksiyonlara değinmeliyiz. Programlama dillerinin en çok kullanılan özelliklerinden biri olan fonksiyonlar, belirli parametreler alarak çalışan ve kendi içinde belirlenen hesaplamayı yaparak cevabı çağrıldığı yere döndürebilen yapılardır. Özellikle uygulamamızın kodlarında birbirini tekrar eden yerler olduğunda veya birçok yerde kullanacağımız bir fonksiyonu defalarca yazmamız gerektiğinde fonksiyonlar yardımımıza koşar. ayrıca fonksiyon kullanmak, bu çok tekrar eden kodlarda herhangi bir değişiklik yapmamız gerekirse tek yerden bu değişikliği bütün uygulama çerçevesinde gerçekleştirmemize olanak verir.

Fonksiyon Kullanımı

Bütün fonksiyonlar stabil bir yapı içerisinde tanımlanır ve fonksiyona ait kodlar geçmiş eğitimlerde gördüğümüz döngülerde olduğu gibi süslü parantezler { ve } arasına yazılır. Yine burada önemli olan, bu parantezler ile kod blokları oluşturduğumuz için parantezi kapattıktan sonra noktalı virgül kullanmamamız gerektiği. Kodumuzu yer aldığı alandan önce fonksiyonun erişim parametreleri, döndüreceği değer, ismi ve varsa aldığı parametreler yazılmalıdır. Fonksiyonlar amaçlarına göre kendi yazıldığı sınıf içerisinde kullanıldığı gibi, başka sınıflar tarafından da ilgili sınıfın bir nesnesi yaratılarak kullanılabilirler. Bir fonksiyonu çağırmak için, eğer aynı sınıf içerisinde ise fonksiyon(parametreler) şeklinde çağırabilir, farklı bir sınıf içerisinde tanımlıysa ileride değineceğimiz şekilde o sınıftan bir nesne yaratarak çağırabiliriz. Bu sayede birçok sınıf birlikte çalışabilir ancak bazı fonksiyonlar sadece o sınıfın kendi iç işleyişi için gereklidir ve o dışarıdan çağırılmaması hatalara neden olmaması adına önemlidir. Bu yüzden fonksiyon tanımlamalarına başlarken ilk önce bir erişim denetliyici parametre kullanarak ilgili fonksiyonun hangi sınıflar tarafından görülebileceğini belirtebiliriz. Kullanabileceğimiz farklı değişkenlerden en önemlileri “public” ve “private”’dir. Eğer bir fonksiyonun uygulamanın bütün sınıfları tarafından çağrılmasında bir sakınca yoksa onu ortak yani “public” olarak tanımlamalıyız. Ancak tersi bir durum içi gizli (private) bir fonksiyon olarak tanımlayarak ilgili sınıf dışından kullanılmasını engelleyebiliriz.

Örnek fonksiyon deklerasyonu

İkinci adım olarak fonksiyonumuzun dönüş parametresini belirlemeliyiz.  Hesap yapmakla görevli bazı fonksiyonlar, hesaplamaları yapacakları değerleri parametre olarak aldıktan sonra, ilgili işlemleri kendi içinde yapar ve yaptığı hesabın sonucunu geri döndürebilir. Biz bu dönen değeri başka bir değişkene atayabilir ya da ekranda yazdırabiliriz. İlk örneğimizde konsolda çalışan basit bir hesap makinesi hazırladık. Burada gördüğünüz gibi Islemler isminde bir sınıfımız bulunmakta ve bu sınıfın içerisinde Topla ve Carp adında iki fonksiyon mevcut. Ondalık sayı değerini ifade eden double türünden değerleri toplayabilen ve çarpabilen bu fonksiyonlar başka sınıflardan da çağırılabildiği için public olarak erişilebilir kılınmış ve sonuç olarak bir ondalık değer döndürebileceğinden double türünden bir dönüş değeri tanımlanmış.

İlk örneğimizin ekran çıktısı

Ancak fonksiyonların her zaman bir değer döndürmeleri zorunlu değildir. Örneğin ekrana yazı yazdıran veya veritabanına girdiler ekleyen bir fonksiyonun çağrıldığı yere bir değer döndürmesi gereksizdir. Böyle durumlarda döndürülecek değerin olmadığını belirten void ifadesi yazarak fonksiyonumuzu tanımlıyoruz. Fonksiyonların döndürmesi gereken değerler olduğunda ise, bu değeri hesaplandıktan sonra return anahtar sözcüğünü kullanılarak çağrıldığı noktaya iletebiliriz. Örneğimizdeki Topla ve Carp fonksiyonları da aldığı değerleri basit olarak matematiksel bir işlem yaptığı için bunları direk return ifadesinin yanında gerçekleştirebiliyoruz. Burada dikkat etmemiz gereken nokta, return ifadesinin fonksiyonu sonlandırdığını bilmek. Bu ifadeden sonra fonksiyondan çıkılacağı için “return”’ü bütün işlemlerini bitirdikten sonra ya da bazı koşullar sağlandığında çıkmak isterseniz if gibi ifadelerin içerisinde kullanmamız gerekiyor.

IntelliSense programcılara çok büyük kolaylı sağlıyor.

Dönüş tipini belirledikten sonra fonksiyonumuza bir isim verip, parantezler içerisinde fonksiyonun alacağı ifadeleri tanımlıyoruz. Fonksiyon içinde kullanılacak parametreler burada vereceğimiz isimler ile anılan lokal değişkenler haline gelirler. Ayrıca parametre isimlerinden önce mutlaka veri tiplerini de belirmemiz gerekmekte.

Sınıf ve Nesneler

Daha önce bahsettiğimiz gibi, belirli fonksiyonların sınıflar altında gruplanarak uygulama içerisinde belirli bir işlevi yürütmeye çalışırlar. Geçtiğimiz eğitimlerden hatırlayacak olursanız, C# ta uygulamalar, Main ismindeki özel bir fonksiyon ile başlar. Yani programımız çalışırken bu Main fonksiyonu aranır ve bütün işlemler bu fonksiyon ile başlatılır. Önemli olan bir nokta, bütün program içerisinde sadece bir adet Main fonksiyonunun olması gerektiğidir. Programımız sahip olduğu nesneleri kullanarak işlevlerini yerine getirir ve sınıflar bu nesnelerin yaratılması için gerekli bir kalıp görevi görür.

Yaratılan nesneler kendi isimleriyle çağırılırlar ve bağlı bulunduğu sınıfın fonksiyonlarını çalıştırmamıza imkân verirler. Bir sınıftan yeni bir nesne yaratmak için ise yeni anlamına gelen “new” anahtar sözcüğünden yararlanıyoruz.

Ornek nesneİsmi = new Ornek();

Şeklinde örnek bir sınıfa dair yeni bir nesne yaratabiliriz. Daha sonra nesneİsmi bu nesnenin referansı haline gelecek ve kodun ilerleyen kısmında bu nesneyi temsil edecektir. Herhangi bir nesnenin içerdiği fonksiyonlara, o nesnenin yanına bir nokta koyarak ulaşabiliriz. Bu gibi durumlarda noktadan sonra ilgili fonksiyonun ismini yazmamız gerekse de Visual Studio’nun IntelliSense adı verilen özelliği, siz nokta işaretini koyduğunuz anda kullanabileceğiniz fonksiyonları imlecin sonunda size listeliyor. Bütün geçerli değişkenleri, fonksiyonları ve aldığı parametreleri görebileceğimiz bu liste gerçekten çok büyük bir zaman avantajı sağlamakta.

Örnek sınıf ve isim uzayı kullanımı

Yeni bir sınıf yaratmak için sağ tarafta bulunan Solution Explorer içerisinde projemize sağ tuşla tıklayıp, New Item -> Class seçeneğini seçebiliriz. Burada görebileceğimiz gibi sınıf (class) ismi otomatik olarak atanacaktır. Burada class anahtar sözcüğünden sonra sınıfımızın ismini yazıyor ve sonraki kod blokları içerisine ilgili kodlarımızı yazıyoruz. Burada dikkat çekici diğer bir ifade ise namespace ifadesiyle tanımlanan isim uzaylarıdır. İsim uzayları c# içerisindeki sınıfların gruplandığı, içerisine toplanan belirli gruptaki sınıfların bir katman olarak kullanılabildiği üst yapıdır. Aynı gruptaki bütün sınıflar, aynı isim uzayı içerisinde çalışmalıdır ve bu isim uzaylarının isimleri namespace ifadesinin yanında belirtilir.

Bütün uygulamalar Main fonksiyonu ile başlarlar..

Sınıflar içerisinde bütün fonksiyonların ve diğer sınıfların görebileceği değişkenler oluşturmak ta mümkündür. Global değişken denilen bu tipler, başına yazılan bir erişim denetleyicisi sayesinde diğer sınıflar tarafından görünebilirliğini değiştirebilir. Fonksiyonlar içerisindeki lokal veriler ile çakışmaması için bu değişkenlere farklı bir isim atamak doğru bir karar. Yine de bir fonksiyon içinde this.GlobalDeğişkenAdı biçiminde bu değişkenlere ulaşmak mümkündür.

Sınıflar için oldukça önemli olan bu global değişkenlerin ilk atamalarının yapılması ise diğer bir önemli konu. Nesneleri oluşturmak için bir kalıp olarak kullandığımız sınıflar, bu değişkenlerin aldığı değerler ile birbirinden farklı nesneler üretebilirler. Bu değişkenlere değer veren fonksiyonlar oluşturabileceğimiz gibi, direk nesne oluşumunda da bu değişkenlere değerini atayabiliriz. Yapılandırıcı (constructor) denilen özel yapılar bir nesne oluşturulmadan bu atamaları ve varsa farklı işlemleri yapmamıza olanak verir.  Yapılandırıcı oluşturmak için herhangi bir dönüş tipi olmayan ve sınıfla aynı isimdeki fonksiyonları kullanırız. Örneğin Arac isimli bir sınıfımız varsa;

public Arac(int hiz, string renk)  { … }

Şeklinde bu sınıfa örnek bir yapılandırıcı oluşturabiliriz. Buradaki “hiz” ve “renk” değerleri, Arac sınıfının ilgili global değişkenlerini atamakta kullanılabilirler. Bu aşamadan sonra yapılandırıcı kullanılarak oluşturulan nesneler gerekli başlangıç değerlerini alarak oluşmuş olurlar. Bir örnek vermek gerekirse, aynı Arac sınıfından bu şekilde yeni nesne yaratabiliriz:

Arac yeniArac = new Arac(180, “mavi”);

Burada new ifadesinin yanında Arac sınıfının yapılandırıcısı doğrultusunda değerler vererek sınıfı başlangıç değerleriyle yaratabiliyoruz. Son olarak ikinci örneğimize bakacak olursak, yarattığımız bir Saat sınıfının saat, dakika ve saniye olmak üzere 3 global değişkeni bulunmakta. Bu değişkenler bir yapılandırıcı sayesinde nesne yaratıldığında değer alıyor ve SaatiGoster fonksiyonu ile ekrana yazdırılıyorlar. Saati gösteren fonksiyonumuzu döneceği bir değer bulunmadığı için void ifadesi ile yaratıyoruz. Konsol uygulamalarında göstereceğimiz bu son örnek ile C# derslerinin bu bölümünü tamamlıyoruz.. Bir sonraki yazıda görüşmek üzere ;)

p.s. Bu yazı Aralık 2008 tarihinde hazırlanmıştır.

İkinci örneğimizin sonuç ekranı

Örnek Kod 1:


//1. Örnek

class Islemler

{

public double Topla(double a, double b)

{

return a + b;

}

public double Carp(double a, double b)

{

return a * b;

}

public static void Main()

{

//Once sınıfımızdan bir nesne yaratıyoruz.

Islemler hm = new Islemler();

//Örnek olarak 10 ve 20 sayısını kullanıyoruz.

Console.WriteLine(“Toplam: ” + hm.Topla(10, 20) + “\nÇarpım: ” + hm.Carp(10, 20));

}

}

Örnek Kod 2:


//2. Örnek

class Saat

{

public int saat;

public int dakika;

public int saniye;

public Saat(int yeniSaat, int yeniDakika, int yeniSaniye)

{

saat = yeniSaat;

dakika = yeniDakika;

saniye = yeniSaniye;

}

public void SaatiGoster()

{

Console.WriteLine("Saatimiz: " + saat + ":" + dakika + ":" + saniye);

}

static void Main(string[] args)

{

//Saat sınıfından yapılandırıcıyı kullanarak bir nesne yaratıyoruz.

Saat saatim = new Saat(22, 10, 56);

//SaatiGoster fonksiyonunu cagiriyoruz.

saatim.SaatiGoster();

}

}

Related posts:

  1. C# Dersleri – 4: Döngü Yapilari
  2. C# Dersleri – 5: Diziler
  3. C# Dersleri – 3: Program Kontrolleri
  4. C# Dersleri – 2: Programciliga Giris
  5. C# Dersleri – 1: .Net Framework