Serdar YILMAZ / Software Developer
Bizimkisi Bir “Bug” Hikayesi...
Akbank Bankacılık Merkezi

Arşiv 'C# Döküman' Kategori

C# – Merkezi İstisnai Durum Yönetimi

.netTry-Catch-Finally blokları ile çalışma anında meydana gelen hataları nasıl yakalayabileceğimizi ve türlerine göre nasıl filtreleyebileceğimizi öğrendik. Hataların türlerine göre filtrelenmesi işleminde bazen Catch bloklarının sayısı bir hayli fazla olabilmekte.

ExampleClass sınıfının içerisinde tanımlanmış olan ExampleMethod_1 ve ExampleMethod_2 metotlarını inceleyecek olursak; Catch bloklarından dolayı metotların gövdesinde kod kalabalığı oluştuğunu görebiliriz. Üstelik henüz metodun görevini ve Catch bloklarının içeriğini yazmadık bile! ExampleMethod_1 ve ExampleMethod_2 gibi içerinde bir çok Catch bloğu barındıran, onlarca metodun oluşturduğu bir sınıftaki kod kalabalığını tahmin edebilirsiniz.

Tüm metotlarda Try-Catch-Finally bloklarını tekrar tekrar yazmak yerine, oluşan hataları yakalayan ve türlerine göre filtreleyen merkezi bir İstisnai Durum Yönetimi metodu oluşturarak, kod kalabalığını ciddi anlamda azaltabiliriz. Bunun için öncelikle yukarıdaki ExampleClass sınıfımızı Try-Catch bloklarından arındırıp, geriye sadece metotların görevlerini yani metotlar çağrıldığında çalışmasını istediğimiz kodları bırakıyoruz.

ExampleClass sınıfındaki Try-Catch bloklarını kaldırarak kod kalabalığını ciddi anlamda azalttık. Şimdi, ExampleMethod_1 ve ExampleMethod_2 metotlarının çalışması esnasında ortaya çıkan hataları yakalayan ve türlerine göre filtreleyen metodumuzu yazıyoruz.

Oluşturduğumuz ExceptionCatcher metodunu dikkatlice inceleyecek olursak; Action türünde bir parametre aldığını görebiliriz. Bu da şu anlama geliyor; biz ExceptionCatcher metoduna parametre olarak bir metot veya kod bloğu gönderebiliriz (Delegate’leri anlatacağım içeriklerde bu konuya daha detaylı bir şekilde değineceğim).

ExceptionCatcher metoduna parametre olarak gönderdiğimiz metotları Invoke() ile çağırmaktayız. Yani toparlayacak olursak; ExceptionCatcher metoduna parametre olarak ExampleMethod_1 ve ExampleMethod_2 metotlarını göndereceğiz ve Invoke() metodu ile bu metotları Try bloğu içerisinde çalıştırıp, hata oluşması durumunda da Catch blokları ile filtreleyeceğiz.

Son olarak ExceptionCatcher metoduna parametre olarak bir metot göndermek yerine, bir kod bloğu göndereceğimiz farklı bir örnek yapalım.

Yukarıdaki uygulamamızda ExceptionCatcher metoduna parametre olarak bölme işlemini gerçekleştiren kod bloğunu gönderdik. Göndermiş olduğumuz kod bloğu ExceptionCatcher metodunun Try bloğunda çalışacaktır. Klavyeden sayı yerine harf veya karakter girildiğinde veya sayi_2 değişkenine sıfır değeri atandığında oluşacak hatalar ilgili Catch bloğu tarafından yakalanacaktır.

Serdar YILMAZ

C# – Exception Sınıfı Oluşturma

.netİstisnai Durum Yönetimi başlıklı yazımızda Try-Catch-Finaly blokları ile uygulamamızda meydana gelen hataları nasıl yakalayacağımıza ve türlerine göre nasıl filtreleyebileceğimize değinmiştik. Bu yazımızda ise; kendi Exception sınıflarımızı nasıl oluşturacağımıza ve hangi amaçlar doğrultusunda kullanabileceğimize değineceğiz.

Hazır Exception Sınıfları

.NET Framework içerisinde bir çok hazır Exception sınıfı bulunmaktadır. Uygulamamızda çalışma anında bir hata meydana geldiğinde .Net,  hatanın türüne göre ilgili Exception sınıfından bir nesne oluşturarak geriye fırlatmaktadır.

Yukarıdaki örneği inceleyecek olursak; Bir sayının sıfıra bölümü sonsuz olduğundan, sayi_1 değişkeni sayi_2 değişkenine bölünmek istendiğinde .Net bir Exception nesnesi fırlatacaktır. Bize düşen ise try-catch blokları ile bu hatayı yakalamaktır. Yukarıdaki uygulama çalıştırıldığı takdirde ekran çıktısı aşağıdaki gibi olacaktır;

Ekran çıktısını inceleyecek olursak; .Net’in sadece hata vermekle kalmadığını, hatanın neden oluştuğuna dair bilgide verdiğini görebiliriz. Tıpkı bu örnekte olduğu gibi, bizlerde hatalı işlem yapılmasını önlemek amacıyla kontrollü bir şekilde Exception’lar fırlatabiliriz.

Kendi Exception Sınıflarımızı Nasıl Oluşturabiliriz ?

Exception sınıflarının nasıl oluşturulduğunu ve kullanıldığını örnek bir senaryo üzerinden ilerleyerek anlamaya çalışalım. Kullanıcıların şifrelerini değiştirebileceği bir metot yazmak istediğimizde, metot içerisinde en basit haliyle aşağıdaki kontrolleri yapabiliriz;

  1. Belirtilen kullanıcı adı sistemimizde var mı? Eğer yoksa olmayan bir kullanıcının şifresi değiştirilmek isteniyor demektir, böylesi bir durumda bir hata mesajı fırlatmamız gerekir.
  2. Şifresini değiştirmek isteyen kullanıcıdan, doğrulama amaçlı eski şifresini girmesini istediğimizde yanlış bir şifre girerse bir hata mesajı döndürmemiz gerekir.

Yukarıdaki iki durumu da dikkate alarak Exception sınıflarımızı oluşturalım;

Kullanıcı sistemimize kayıtlı olmadığı durumda fırlatacağımız UserNotFoundException ve yanlış şifre girildiği zaman fırlatacağımız WrongPasswordException sınıflarımızı oluşturduk. Dikkat edilecek olursa her iki sınıfımızda Exception sınıfından türetilmiştir ve base anahtar sözcüğü ile hata mesajları temel sınıf olan Exception sınıfının yapıcı metoduna parametre olarak gönderilmiştir.

Oluşturacağımız Exception sınıfları, “Exception” sınıfından türetilmelidir.

base anahtar sözcüğünün kullanımı hakkında daha detaylı bilgi edinmek için Yapıcı Metotlar ve Kalıtım başlıklı içeriği okuyabilirsiniz.

Nasıl Exception Fırlatabiliriz ? 

Exception sınıflarımızı oluşturduğumuza göre şimdi onları hatalı işlem yapılmasını önlemek amacıyla kontrollü bir şekilde fırlatabiliriz. Örnek senaryo üzerinden giderek sınıfımızı ve metodumuzu oluşturalım;

UserManager isimli class içerisinde kod kalabalığını arttırmamak için; kullanıcı adı ve şifre çiftlerini tutan bir Dictionary tanımlayıp, kullanıcının kayıt olup-olmadığını, şifrenin doğru girilip-girilmediğini bu koleksiyon sınıfı üzerinden kontrol ettik. Sizler bu işlemleri veritabanı üzerinden yapabilirsiniz. Dictionary hakkında daha detaylı bilgi edinmek için Dictionary Sınıfı başlıklı içeriği okuyabilirsiniz.

PasswordChange() isimli metodumuzu açıklayacak olursak; İlk olarak parametre olarak gelen kullanıcı adının _Users koleksiyonunda olup olmadığını kontrol ediliyor ve eğer kullanıcı mevcut değilse throw anahtar sözcüğü ile UserNotFoundException istisnası fırlatılıyor. Kullanıcı mevcut ise parametre olarak gelen şifre bilgisinin doğru olup olmadığı kontrol ediliyor ve şifre bilgisi yanlış ise WrongPasswordException istisnası fırlatılıyor. Doğru girildiği takdirde de ilgili kullanıcının şifre bilgisini güncelleniyor.

throw anahtar sözcüğü ile oluşturduğumuz exception sınıflarını nasıl fırlatacağımızı öğrendik, şimdi sıra onları yakalamakta.

_Users koleksiyonunda “serdaryilmaz” adında bir kullanıcı olmadığı için UserNotFoundException istisnasını fırlatacaktır. Ekran çıktısı;

“srdrylmz” kullanıcısının şifresi yanlış girildiğinden WrongPasswordException istisnasını fırlatacaktır.

Serdar YILMAZ

C# – İstisnai Durum Yönetimi

.netUygulamalarımızı geliştirirken bir syntax hatası (Kod satırlarının sonuna noktalı virgül koymayı unutmak gibi) yaptığımızda, Visual Studio gerekli uyarıyı vererek projeyi derlememizi engelleyecektir. Ancak çalışma anında ortaya çıkabilecek hataları Visual Studio’nun önceden tespit edebilmesi mümkün değildir. Bu yüzden çalışma anında ortaya çıkabilecek hataların uygulamamızı çökertmesine izin vermemek için Try-Catch-Finally ile istisnai durum yönetimine başvururuz.

Yukarıdaki uygulama Visual Studio tarafından sorunsuz bir şekilde derlenecektir ve doğru değerler girildiği sürece program sorunsuz bir şekilde çalışacaktır.  Ancak programı kullanan kullanıcı klavyeden sayı yerine harf veya karakter girdiğinde veya sayi_2 değişkenine sıfır değerini atadığında (bir sayının sıfıra bölümü sonsuzdur) uygulamamız çökecektir.

Çalışma anında ortaya çıkan hataların uygulamamızı çökertmemesi için Try-Catch-Finally bloklarını kullanırız.

Try-Catch-Finally Blokları

Try Bloğu: Çalışma anında hata çıkarma olasılığı olan kodlarımızı Try bloğu içerisine yazarız. Eğer Try bloğu içerisine yazılmış olan kodlarda bir hata meydana gelirse, oluşan hata bir Exception nesnesi olarak catch bloğuna gönderilir.

Catch Bloğu: Try bloğu içerisine yazılmış olan kodlarda bir hata meydana geldiği an, program Try bloğundan çıkarak Catch bloğuna girer. Uygulamamız çalışırken hata oluşması durumunda, uygulanmasını istediğimiz çözüm senaryosunu Catch bloğu içerisine yazarız.

Finally Bloğu: Try bloğu içerisinde bir hata meydana gelmediği sürece Catch bloğu içerisindeki kodlar çalışmaz. Ancak Finally Bloğu hata meydana gelse de, gelmese de her halükarda çalışır. Finally opsiyonel bir bloktur, istenilmediği taktirde yazılmayabilir.

Artık sayı yerine harf girildiğinde veya sayi_2 değişkenine sıfır değeri atandığında uygulamamız çökmeyecektir. Hata meydana geldiği an arkaplanda bir Exception nesnesi oluşturulup Catch bloguna parametre olarak gönderilecektir. Bu parametre aracılığıyla oluşan hata hakkında bilgi alınabilir.


Yukarıdaki örnekte Exception’da ki hata mesajı kullanıcıya gösterilmek üzere ekrana yazdırıldı ancak profesyonelce geliştirilen projelerde Exception’da ki hata mesajı doğrudan kullanıcıya sunulmaz. Bunun başlıca iki sebebi bulunmaktadır.

  1. Exception’da ki hata mesajı genellikle kullanıcıların anlayamayacağı teknik terimleri içerir.
  2. Exception’da ki hata mesajı uygulamamız hakkında bilinmemesi gereken bilgileri içeriyor olabilir.

Bu yüzden Exception’da ki hata mesajını genellikle loglamak amacıyla kullanırız.

Oluşan Hataları Filtreleme

Try bloğu içerisine yazdığımız kodlarda farklı türden hatalar meydana gelebilir. Eğer her hata türü için farklı bir çözüm senaryomuz varsa, oluşan hataları filtrelememiz gerekir. Yukarıdaki örneğimizde iki farklı hata söz konusuydu; ilki klavyeden sayı yerine harf veya karakter girildiğinde ortaya çıkarken, ikincisi sayi_2 değişkenine sıfır değeri atandığında ortaya çıkmaktaydı. Oluşan hataları filtreleyecek şekilde uygulamamızı yeniden yazacak olursak;

“FormatException” ve “DivideByZeroException” gibi bir çok hazır Exception sınıfı bulunmakta. Try bloğunda hata meydana geldiği an arkaplanda bir Exception nesnesi oluşturulur ve Catch blokları yukarıdan aşağıya incelenir, oluşan hata türü hangi Catch bloğuna uyuyorsa o Catch bloğu çalışır. Klavyeden sayı yerine harf veya karakter girildiğinde ilk Catch bloğu çalışacaktır, sayi_2 değişkenine sıfır değeri atandığında da ikinci Catch bloğu çalışacaktır. “FormatException” ve “DivideByZeroException” haricinde bir hata meydana geldiğinde de üçüncü Catch bloğu çalışacaktır.

“catch(Exception exception)” şeklinde tanımlanan Catch bloğu tüm hata türlerini kapsar. O yüzden hata türüne göre filtreleme işlemi yaparken “catch(Exception exception)” bloğunu en sona yazmalıyız.

Eğer “catch (Exception exception)” bloğunu en üste yazarsak; Catch blokları yukarıdan aşağıya doğru incelendiği için ve “catch (Exception exception)” bloğu da tüm hata türlerini kapsadığı için;  “catch (FormatException exception)” ve “catch (DivideByZeroException exception)” blokları hiç bir zaman çalışmayacaktır. Tüm hata türleri “catch (Exception exception)” bloğu tarafından yakalanacaktır.

Serdar YILMAZ

C# – Abstract Sınıflar

.netTamamen kalıtım amaçlı kullanacağımız temel sınıfları oluştururken Abstract anahtar sözcüğünü kullanırız. Abstract bir sınıf oluşturabilmek için erişim belirtecinden sonra “abstract” anahtar sözcüğünü yazmamız gerekmektedir. Abstract sınıflar içerisinde hem metot tanımlayabilir hem de arayüzler de olduğu gibi metot bildirimi yapabiliriz.

TemelSinif, abstract bir sınıf olduğu için sadece kalıtım amaçlı kullanılabilir. Metot_1(), TemelSinif‘dan türetilen sınıflara doğrudan aktarılacaktır. Bildirimi yapılmış olan Metot_2()‘nin ise türetilmiş sınıflar içerisinde tanımlanması (metot gövdesinin yazılması) gerekmektedir.

Abstract sınıflarda metot bildirimi yapabilmek için erişim belirtecinden sonra “abstract” anahtar sözcüğünü yazmamız gerekmektedir.

TuretilmisSınıf, TemelSinif‘dan türetildiği için TuretilmisSınıf içerisinde Metot_2()‘nin tanımlamasını yapmamız gerekmektedir. Bu örnekten de anlaşılacağı üzere abstract sınıfları arayüzler (interface) gibi kullanabiliriz.

Abstract sınıf içerisinde bildirimi yapılmış olan metotları (Bkz: Metot_2()) türetilmiş sınıflar içerisinde tanımlayabilmemiz için override anahtar sözcüğünü kullanmamız gerekmektedir.

Ekran çıktısı:

Abstract Sınıfların Normal Sınıflardan Farkı Nedir?

Fark 1: Normal sınıflar içerisinde metot bildirimi yapılamazken, Abstract sınıflar içerisinde tıpkı arayüzler de olduğu gibi metot bildirimi yapılabilir. Bildirimi yapılan metotlar, Abstract sınıftan türeyen sınıflar içerisinde tanımlanmak zorundadır.

Fark 2: Normal sınıflardan “new()” anahtar sözcüğü ile nesneler oluşturulabilir ancak Abstract sınıflar tamamen kalıtım amaçlı geliştirildiğinden Abstract sınıflardan nesne oluşturulamaz.

Abstract Sınıfların Arayüzlerden Farkı Nedir?

Fark 1: Arayüzlerde sadece metot bildirimi yapılabilirken Abstract sınıflarda hem metot bildirimi yapılabilir hem de metot tanımlanabilir.

Fark 2: Bir sınıfa sadece bir tane Abstract sınıf inherit edilebilir ancak aynı sınıfa birden fazla arayüz implement edilebilir.

TuretilmisSinif‘a Abstract sınıflardan sadece bir tanesini inherit edebiliriz. Yani TuretilmisSinif‘a hem AbstractSinif_1‘i hem de AbstractSinif_2‘yi inherit edemeyiz.

Ancak bir Abstract sınıfa, başka bir Abstract sınıfı inherit ederek bu kısıtı kaldırmak mümkün.

AbstractSinif_1‘e AbstractSinif_2 inherit edildiği için, AbstractSinif_1‘den türetilen bir sınıf hem AbstractSinif_1 içerisinde bildirimi yapılmış olan metodu (Metot_1()) hem de AbstractSinif_2 içerisinde bildirimi yapılmış olan metodu (Metot_2()) içermek zorundadır.

Abstract Sınıflara Hangi Durumlar da İhtiyaç Duyarız

Yılın her bir ayı için bir sınıf oluşturmamız gerektiğini düşünelim ve bu sınıflar içerisinde ilgili ayın kaç günden oluştuğu, yılın kaçıncı ayı olduğu ve her bir gününün kaç saatten oluştuğu bilgilerini döndürecek metotların olmasını istediğimizi varsayalım.

İlk başta aklımıza bir arayüz kullanmak gelebilir. Ay isminde bir arayüz tanımlayıp, içerisinde ihtiyacımız olan metotların bildirimini yaptıktan sonra bu arayüzü aylarımızı temsil eden sınıflara implement ederek bir çözüm geliştirebiliriz.

Ancak ayları temsil eden sınıfları dikkatlice inceleyecek olursak, GunlerKacSaattir() metodunun hepsinde aynı sonucu döndürecek şekilde tanımlandığını görebiliriz. Her bir ay için aynı metodu tekrar tekrar tanımlayıp kod tekrarı yapmak yerine, bir defaya mahsus tanımlamak çok daha verimli olacaktır. Arayüzler içerisinde metot tanımı yapılamayacağından, bu örnekte arayüz yerine abstract sınıf kullanacağız.

İçerisinde hem metot tanımı hem de metot bildirimi yapabileceğimiz bir yapıya ihtiyacımız olduğundan Ay isminden bir abstract sınıf oluşturduk. GunlerKacSaattir() metodu tüm aylar için aynı sonucu döndüreceğinden, bu metodu direkt abstract sınıf içerisinde tanımladık. Böylece 12 ay için aynı metodu 12 defa yazmak yerine, bir defa yazmış olduk.

Eğer bir metot tüm türetilmiş sınıflarda aynı şekilde tanımlanıyorsa o metodu abstract sınıf içerisinde standart bir metot tanımlar gibi tanımlarız.

KacGundenOlusur() metodunu abstract sınıf içerisinde tanımlamak yerine sadece bildirimini yapıp, Ayları temsil eden sınıflarımız içerinde tanımlayabilirdik. Ancak bu metot Ocak, Mart, Mayıs, Temmuz, Ağustos, Ekim ve Aralık ayları için aynı sonucu (31) döndürmesi gerektiğinden, en azından bu aylar için tekrardan KacGundenOlusur() metodunun tanımını yapmamak adına varsayılan olarak geriye 31 döndüren ancak istenilen sınıf içerisinde override edilerek yeniden tanımlanabilecek şekilde kullanılabilmesi için virtual olarak tanımladık (Bkz: C# – Virtual Metotlar).

Eğer bir metot bir çok türetilmiş sınıfta aynı şekilde tanımlanıyor iken sadece bir kaçında değişik şekilde tanımlanıyorsa o metot abstract sınıf içerisinde virtual olarak tanımlanır.

YilinKacinciAyidir() metodu her bir ay için farklı bir değer döndüreceğinden, bu metodun sadece bildirimi yapıyoruz.

Eğer bir metot tüm türetilmiş sınıflarda farklı şekilde tanımlanıyorsa o metodun abstract sınıf içerisinde sadece bildirimi yapılır.

Serdar YILMAZ

C# – Virtual Metotlar

.netKalıtım yolu ile sınıfların birbirinden türetilebileceğini ve bir sınıfın diğer bir sınıftan türediği zaman, türediği sınıfın bütün özelliklerini içereceğini “C# – Kalıtım” başlıklı içeriğimizde açıklamıştık.

Temel sınıftan türetilmiş sınıflara aktarılan metotları her zaman olduğu gibi kullanmak istemeyebiliriz. Bu metotları türetilmiş sınıf içerisinde yeniden tanımlayabilmek için virtual ve override anahtar sözcüklerini kullanırız.

Virtual metotlar kalıtım yolu ile aktarıldıkları sınıfların içerisinde override edilerek değiştirilebilirler. Eğer override edilmezlerse temel sınıf içerisinde tanımlandıkları şekilde çalışırlar.

Kod kalabalığını arttırmamak ve konuyu daha anlaşılır bir şekilde anlatmak için; sınıfları karışıklığa yer vermeyecek şekilde isimlendirip, konumuzun dışında olan kod satırlarına/bloklarına yer vermemeye çalışacağım.

Örnek bir senaryo üzerinden gidecek olursak; User (kullanıcı), Category (kategori) ve Article (Makale) isimli sınıflarımızın olduğunu ve bu sınıfların Database sınıfından türetildiğini düşünelim.

Database sınıfı içerisindeki Insert() metodu kalıtım yolu ile User, Category ve Article sınıflarına aktarılacaktır.

Yukarıdaki konsol uygulamasının ekran çıktısı;

Ancak biz User sınıfında Insert() metodunun kullanıcı adı kontrolü yaptıktan sonra veriyi kaydetmesini istiyor olabiliriz. Temel sınıf içerisindeki bir metodun gövdesini türetilmiş sınıflar içerisinde değiştirebilmek için Temel sınıf içerisindeki metodu virtual olarak tanımlamamız gerekir.

Database sınıfı içerisindeki Insert() metodu virtual olarak belirtildiği için User sınıfı içerisinde override edilerek gövdesi değiştirildi. override edilmiş bir metot içerisinden metodun orijinalini (temel sınıf içerisindeki halini) çağırabilmek için base anahtar sözcüğü kullanılır.

Konsol uygulamamızı tekrar çalıştıracak olursak ekran çıktısı aşağıdaki gibi olacaktır.

Serdar YILMAZ

C# – Arayüzler

.netArayüzler, sınıflara rehberlik etmek üzere oluşturulan nesneye dayalı programlamanın en önemli özelliklerinden biridir. Sınıfların hangi metotları ve özellikleri içermesi gerektiğini arayüzler içerisinde bildiriyoruz.

Arayüz Oluşturma

Arayüzler “interface” anahtar sözcüğü ile oluşturulur. Zorunlu olmamakla birlikte arayüz isimleri genellikle “I” harfiyle başlatılır. Böylece “I” ön ekini gören bir programcı onun bir arayüz olduğunu anlar. Arayüz içerisinde özelliklerin ve metotların sadece bildirimi yapılır. Yani herhangi bir şekilde özelliklere bir değer atanmaz sadece türleri ve isimleri yazılır, aynı şekilde metotların içerisine kodlar yazılmaz sadece geri dönüş türleri ve isimleri yazılır. 

Arayüzlerin Sınıflara İmplement Edilmesi

IKisi arayüzü, Yonetici sınıfına implement edildiği için (1.Satır) Yonetici sınıfı, IKisi arayüzünde bildirimi yapılmış olan özellikleri ve metotları içermek zorundadır. Yonetici sınıfı içerisine, IKisi arayüzünde bildirimi yapılmış metotlar ve özellikler haricinde Yonetici sınıfına has metotlar ve özellikler de tanımlanabilir. 

Arayüzlere Neden İhtiyaç Duyarız?

Arayüzlerin geniş bir kullanım alanı bulunmaktadır. Basit bir örnek üzerinden anlatacak olursak; 

Arayüz kullanımı sınıflarımızı bir standart çerçevesinde yapılandırmamızı sağlamaktadır. IKisi arayüzünün Isci ve Yonetici sınıflarına implement edildiğini gören bir programcı, bu sınıfların içerisinde adSoyad, adres, departman gibi özelliklerin olduğunu ve bu özelliklere erişilerek gerekli bilgilerin alınabileceğini bilecektir.

Örneğin, Yonetici ve Isci sınıflarından oluşturulan nesnelerin içerisindeki adSoyad özelliğini ekrana yazdıran bir metot yazalım. Arayüzlerin sağlamış olduğu kolaylıktan faydalanmıyor olsaydık bu işlemi aşağıdaki gibi yapıyor olurduk;

İki farklı metot tanımlamamız gerekirdi. Bu metotlardan biri Yonetici sınıfı türünden parametre alırken, diğeri Isci sınıfı türünden parametre alırdı. Ancak arayüzler sayesinde bu işlemi tek bir metot yazarak yapabiliriz.

IKisi arayüzü, Yonetici ve Isci sınıflarına implement edildiği için bu sınıflardan oluşturulan nesneler, IKisi arayüzü türündeki bir parametrede tutulabilir. Bu yüzden adSoyadBilgisi() metoduna parametre olarak Yonetici veya Isci sınıfından oluşturulan nesneleri gönderebiliriz. Bu parametre aracılığı ile ilgili nesnelerin sadece IKisi arayüzünden gelen özellik ve metotlarına erişebiliriz.

Çoklu İmplementasyon 

Bir sınıfa birden fazla arayüz implement edilebilir. Örnek bir senaryo üzerinden konuyu anlatacak olursak; Bir fabrika için otomasyon programı yazdığımızı düşünelim. Fabrikada 3 farklı çalışan türü olsun, bunlar yönetici, işçi ve robot. Her bir çalışanın ID, ad-soyad, adres, maaş, departman ve toplam çalışma saati bilgisi olsun. 

Eğer arayüz tasarımını yukarıdaki gibi yaparsak ICalisan arayüzünü, oluşturacağımız Yonetici ve Isci sınıflarına implement edebiliriz ancak Robot sınıfına implement edemeyiz. Çünkü robotların adlarının ve adreslerinin olmayacağını ve maaş almayacaklarını biliyoruz. Bu yüzden ICalisan arayüzünü uygun bir şekilde parçalamamız gerekiyor. 

ICalisan ve IKisi şeklinde iki arayüz oluşturduk. Yöneticiler ve işçiler hem çalışan hemde birer kişi olduğundan, bu sınıflara hem ICalisan arayüzünü hem de IKisi arayüzünü imlement edeceğiz. Robot sınıfına ise sadece ICalisan arayüzünü implement edeceğiz. 

Kurumsal Mimarilerde Arayüz Kullanımı

Daha önce kurumsal mimaride bir uygulama geliştirmediyseniz bu bölümü şimdilik atlayabilirsiniz. 

Bu başlıkta olabildiğince yalın bir şekilde arayüzlerin kurumsal mimarilerde ki kullanımına bir örnek vermeye çalışacağım. Kod kalabalığını arttırmamak ve konuyu daha anlaşılır bir şekilde anlatmak için sınıfları karışıklığa yer vermeyecek şekilde isimlendirip, konumuzun dışında olan kod satırlarına/bloklarına (veritabanı sorguları) yer vermemeye çalışacağım.

Bir projede farklı veritabanı yönetim sistemleri kullanılabilir. Projelerimizi bizden fazla veritabanı yönetim sistemine destek verecek şekilde geliştirebilmek için arayüzlerden faydalanabiliriz. 

Öncelikle IRepository adını verdiğimiz arayüzün içerisinde, veritabanı üzerinde ekleme, silme, güncelleme, kaydetme gibi temel işlemleri yapacak metotların bildirimini yapıyoruz. Sonra bu arayüzü, farklı veritabanı yönetim sistemleri üzerinde işlem yapacak olan sınıflara implement ediyoruz. 

Projemizin hem Oracle veritabanına hemde MsSQL veritabanına destek vermesini istiyorsak; IRepository arayüzü içerisinde bildirimi yapılan metotları, OracleDB sınıfında Oracle vertabanında işlem yapacak şekilde, MsSQLDB sınıfında MsSQL veritabanında işlem yapacak şekilde yazmamız gerekiyor.

MsSQLDB ve OracleDB sınıfları ile artık hem MsSQL veritabanında hem de Oracle veritabanında işlem yapabiliyoruz.

Son olarak ExampleManager isimli bir sınıf oluşturuyoruz, bu sınıftan nesne oluştururken yapıcı metoduna parametre olarak MsSQLDB sınıfından bir nesne gönderirsek ekleme, silme, güncelleme, kaydetme işlemini MsSQL veritabanı üzerinde yapacaktır, OracleDB sınıfından bir nesne gönderirsek de Oracle veritabanı üzerinde yapacaktır. 

Ekran Çıktısı:

Serdar YILMAZ

C# – Temel ve Türetilmiş Sınıf Referansları

dotnetC#’da farklı türden referansların birbirine aktarılması yasaklanmıştır. Örneğin, A ve B isminde iki sınıfımız olsun. A sınıfından oluşturulan bir nesnenin adresini B sınıfından oluşturulan bir referansta tutamayız, aynı şekilde B sınıfından oluşturulan bir nesnenin adresini de A sınıfından oluşturulan bir referansta tutamayız.

Kalıtım ile Türetilmiş sınıftan oluşturulan bir nesnenin adresini, Temel sınıftan oluşturulan bir referansta tutabiliriz.

Kedi ve Insan sınıfı Memeli sınıfından Türetilmiştir. Bu durum da Memeli sınıfı Temel sınıf, Insan ve Kedi sınıfı da Türetilmiş sınıftır.

Açıklama satırlarında da belirtildiği üzere; Insan ve Kedi sınıfları Memeli sınıfından türetildiği için bu sınıflardan oluşturulan nesnelerin adresleri Memeli sınıfından oluşturulan referanslarda tutulabilir. Yalnız burada dikkat edilmesi gereken çok önemli bir husus bulunmakta. Memeli sınıfını inceleyecek olursak içerisinde “TurBilgisi()” adında bir metodun olmadığını görürüz. Bu yüzden Insan veya Kedi sınıfından oluşturulan bir nesnenin adresini Memeli sınıfından oluşturulan bir referansa aktardığımız taktirde “TurBilgisi()” metoduna erişemeyiz. Çünkü Memeli sınıfı içerisinde böyle bir metot bulunmamaktadır.

C# Kalıtım

Türetilmiş sınıf, temel sınıf içerisindeki değişkenleri ve metotları kendi içerisinde tanımlanmış gibi kullanabilir. Ancak temel sınıf, türetilmiş sınıftaki değişkenleri ve metotları kullanamaz.

Insan ve Kedi sınıfları, Memeli sınıfından türetildiği için “Bilgi()” metoduna Insan ve Kedi sınıfından oluşturulan nesnelerin referanslarını parametre olarak gönderebiliriz.

Serdar YILMAZ

C# – Üye Gizleme

dotnetTemel sınıf içerisinde bulunan elemanlardan public ve protected erişim belirteçli olanların kalıtım yoluyla Türetilmiş sınıfa aktarıldığından bahsetmiştik (Bkz: C# – Kalıtım). Peki Temel sınıfta ve Türetilmiş sınıfta aynı isme sahip elemanlar tanımlarsak ne olur?

A Temel sınıf, B ise Türetilmiş sınıftır. Temel sınıfta ve Türetilmiş sınıfta aynı isme sahip elemanlar tanımladığımız için Visual Studio uyarı verecektir. Bu uyarının sebebi; Türetilmiş sınıf içerisindeki elemanların, aynı isimli Temel sınıf elemanlarını gizlemesinden kaynaklanmaktadır.

Türetilmiş sınıfın elemanları Temel sınıfın elemanlarını gizlediği için B sınıfından bir nesne oluşturup “Uye_1” ve “Uye_2” elemanlarına erişmek istediğimiz de B sınıfı içerisinde tanımlanmış olan “Uye_1” ve “Uye_2” elemanlarına erişebiliriz. Ekran çıktısı;

Üye gizleme olayının gerçekleştiği durumlar da Visual Studio bu işlemi yanlışlıkla yaptığımızı düşünerek bize bir uyarı verecektir. Bu işlemi kontrollü bir şekilde yaptığımızı belirtmek için new anahtar sözcüğünü kullanırız.

Yapmış olduğumuz düzenlemeden sonra Visual Studio artık uyarı vermeyecektir. Peki Temel sınıf içerisinde ki “Uye_1” ve “Uye_2” elemanlarına nasıl erişebiliriz ?

Temel sınıf içerisindeki “Uye_1” ve “Uye_2” elemanlarına Türetilmiş sınıf içerisinden erişebilmek için base anahtar sözcüğünü kullanırız. Base anahtar sözcüğü türetmenin yapıldığı temel sınıfı temsil eder. Base anahtar sözcüğünün kullanımına Yapıcı Metotlar ve Kalıtım konusunda da değinmiştik.

Serdar YILMAZ

C# – Yapıcı Metotlar ve Kalıtım

dotnetTüretilmiş sınıftan bir nesne oluşturduğumuz da önce temel sınıfın yapıcı metodu sonra da türetilmiş sınıfın yapıcı metodu çalışacaktır.

A temel sınıf, B ise türetilmiş sınıftır. Bu yüzden B sınıfından bir nesne oluşturduğumuz da (B nesne=new B();) önce A sınıfının yapıcı metodu sonra da B sınıfının yapıcı metodu çalışacaktır.  Ekran çıktısı;

Her yapıcı metodun kendi tanımlandığı sınıfın üye elemanları ile ilgili iş yapması gerekir.

base Anahtar Sözcüğü

Türetilmiş sınıf içerisinden temel sınıfın elemanlarına erişmek için base anahtar sözcüğünü kullanırız.

A temel sınıf, B ise türetilmiş sınıftır. Temel sınıfın yapıcı metoduna türetilmiş sınıf üzerinden parametre gönderebilmek için base anahtar sözcüğünü kullanırız.

B sınıfından nesne oluştururken girdiğimiz birinci(10) ve ikinci(15) parametreler A sınıfının yapıcı metoduna gönderilecektir. Üçüncü(20) ve dördünce(25) parametreler ise B sınıfının yapıcı metodu içerisinde kullanılacaktır. Ekran çıktısı;

Türetme ile sınıflar arasında hiyerarşik bir yapı sağlanır.

base anahtar sözcüğü C sınıfında B sınıfını; B sınıfında da A sınıfını temsil eder. C sınıfından bir nesne oluşturduğumuz da önce A sınıfının yapıcı metodu, sonra B sınıfının yapıcı metodu en son da C sınıfının yapıcı metodu çalışacaktır.

C sınıfından nesne oluştururken girdiğimiz birinci(10) ve ikinci(15) parametreler B sınıfının yapıcı metoduna gönderilecektir. Üçüncü(20) parametre ise C sınıfının yapıcı metodu içerisinde kullanılacaktır. B sınıfına gönderilen birinci(10) ve ikinci(15) parametrelerden ilki(10) A sınıfının yapıcı metoduna gönderilecektir ve ikinci(15) parametre de B sınıfı içerisinde kullanılacaktır.

Serdar YILMAZ

C# – Kalıtım

dotnetKalıtım, nesneye dayalı programlamanın en önemli özelliklerinden biridir. Kalıtım yolu ile sınıflar birbirinden türetilebilir. Bir sınıf diğer bir sınıftan türediği zaman, türediği sınıfın bütün özelliklerini içerir. Bunun yanında kendine has özellikler de barındırabilir.

Yukarıdaki örnekte; A temel sınıf, B ise türetilmiş sınıftır. Türetme işlemi “class B : A” kodu ile 11. satırda yapılmıştır. B sınıfı A sınıfından türetildiği için A sınıfı içerisindeki değişken ve metodu kalıtım yolu ile almaktadır.

Türetme işleminden dolayı B sınıfı, A sınıfı içerisindeki “degisken_1” ve “Metot_1()” elemanlarını kendi içerisinde tanımlanmış gibi kullanabilmektedir.

Türetilmiş sınıf, temel sınıf içerisindeki değişkenleri ve metotları kendi içerisinde tanımlanmış gibi kullanabilir. Ancak temel sınıf, türetilmiş sınıftaki değişkenleri ve metotları kullanamaz.

Erişim Belirteçleri

Türetilmiş bir sınıfa, temel sınıftaki elemanlardan sadece public ve protected olarak tanımlananlar aktarılır. Erişim belirteci private olan elemanlar kalıtım ile aktarılmaz.

Erişim Belirleyicisi: Metot ve özelliklere olan erişimin sınırlarını belirtmektedir. (Bknz: C# – Sınıflar)

  1. Private: Sadece tanımlandığı sınıf içerisinden erişilebilir. (Kalıtım ile aktarılmaz.)
  2. Public: Her yerden erişilebilir. (Kalıtım ile aktarılır.)
  3. Internal: Sadece bulunduğu projede erişilebilir. (Kalıtım ile aktarılır.)
  4. Protected: Tanımlandığı sınıfta ve o sınıfı miras (kalıtım) alan sınıflardan erişilebilir. (Kalıtım ile aktarılır.)

TemelSinif içerisindeki degisken_3‘ün erişim belirteci private olduğu için TuretilmisSinif‘a aktarılmaz. Sadece TemelSinif içerisinde kullanılabilir.

TemelSinif içerisindeki degisken_2‘nin erişim belirteci public olduğu için TuretilmisSinif‘a aktarılır. Yukarıdaki örnekte TuretilmisSinif içerisinde degisken_2 adında bir değişken tanımlanmamış olmasına rağmen TemelSinif‘tan kalıtım aldığı için Metot_2() içerisinde kullanılabilmiştir.

TemelSinif içerisindeki degisken_1‘in erişim belirteci protected olduğu için TuretilmisSinif‘a aktarılır. Yukarıdaki örnekte TuretilmisSinif içerisinde degisken_1 adında bir değişken tanımlanmamış olmasına rağmen TemelSinif‘tan kalıtım aldığı için Metot_1() içerisinde kullanılabilmiştir.

Peki bu durum da public ile protected belirteçleri arasındaki fark nedir? 

Kalıtım

TemelSinif‘dan TuretilmisSinif‘a kalıtım yoluyla aktardığımız “degisken_1 (protected)” ve “degisken_2 (public)” elemanlarını TuretilmisSinif içerisinde kullanabiliriz. Ancak TuretilmisSinif‘dan oluşturduğumuz bir nesne üzerinden sadece “degisken_2” elemanına erişebiliriz. Erişim belirteci protected olan degisken_1 elemanına başka bir sınıftan erişemeyiz. Bunun nedeni; Erişim belirteci protected olan elemanlar tanımlandıkları sınıfta ve  kalıtım yolu ile aktarıldıkları sınıflar da private elemanların özelliklerini gösterirler.

Erişim belirteci protected olan elemanların private elemanlardan tek farkı kalıtım yolu ile aktarılabiliyor olmalarıdır. Eğer türeme söz konusu değilse protected olarak bildirilen elemanlarla private olarak bildirilen elemanlar arasında bir fark kalmaz. Erişim belirteci protected olan elemanları, kalıtım yolu ile aktarılabilen private elemanlar olarak düşünebiliriz.

Serdar YILMAZ