C#’ta Çoklu Kalıtım(Multiple Inheritance)
Her C# yazılımcısının bildiği gibi “Inheritance” konusunda tek tip kalıtım söz konusudur.Yani bir sınıf sadece ve sadece bir sınıftan türeyebilir.Bu gelenek .NET mimarisinin çoklu kalıtıma izin veren C++ dilindeki “Diamond Problem” isimli hatayı ibret almasından dolayı kaynaklanmaktadır.Bu yazımda C#’ta çoklu kalıtımın nasıl yapılacağını inceleyeceğiz.Sizlerin “Interface yapısıyla bu işlemi hallediyoruz zaten” gibi söylendiğinizi duyar gibiyim.Lakin bu yazının ana şablonu çoklu kalıtımı interface yapılarıyla değil, sınıf yapılarıyla göstermektir.Şimdi gelin C#’ta çoklu kalıtım konusunu yasaklanma sebepleriyle beraber ele alalım.
C++ dilinde bir sınıfın birden fazla sınıftan kalıtım alabildiğini yukarılarda bahsetmiştik.Kalıtım hiyerarşisinde bulunan base sınıflarda virtual yapılarına sahip elemanlar varsa eğer ve bu base sınıflardan kalıtım alan tekil sınıflar virtual sınıfları eziyorsa(override) bir sıkıntı söz konusu değildir.Lakin bu derived class yapılarına sahip sınıflar C++ özelliği gereğince tek sınıfa çoklu kalıtım vererek o sınıfta da base classlardan gelen virtual metod override edilirse eğer işte burada C++ dilinin kafası karışıyor ve derleyici hata veriyor.Bunun sebebi, çoklu kalıtım alan sınıfın override ettiği elemanı hangi üst sınıftan aldığını mimarinin bilememesidir.
İşte bu olası duruma C++ dilinde “Diamond Problem” ismi verilmektedir.
Bu anlatımın ne kadar karışık ve anlaması zor olduğunu biliyorum.Ama konumuzu sırf bu hata sebebine odaklamamak için bu tarz bir anlatımdan sonra aktarmak istediğim ana konuya giriş yapmak istiyorum.
C# dilinde çoklu kalıtım yapabilmenin birinci yolu interface yapılarını kullanabilmekten geçer.Kısaca değinmek gerekirse, C# mimarisinde bir sınıf sadece ve sadece bir sınıftan türeyebilir ama bir ve birden fazla interface yapısından da kalıtım alabilir.
Bu yazının ana konusu olan ikinci yola gelirsek eğer bunu somut kodlarla göstermek daha faydalı olacaktır.
“A.cs”, “B.cs” ve “C.cs” isimli üç adet sınıf oluşturalım ve içerikleri aşağıdaki gibi olsun.
class A { public string AdSoyad() { return "Gençay Yıldız"; } }
class B { public string Memleket() { return "Artvin"; } }
class C { }
Gördüğünüz gibi “A.cs” isimli sınıf içerisinde “AdSoyad” isimli bir metod, “B.cs” sınıf içerisinde ise “Memleket” isimli metodumuz bulunmaktadır.”C.cs” isimli sınıfımızda ise bu iki metottan kalıtım almaya çalışacak sınıfımızdır.
Hepimiz biliyoruz ki derleyici aşağıdaki gibi bir kalıtım tekniğine müsade etmeyecektir.
--- HATA --- class C:A, B { }
Ben istiyorum ki, “C.cs” sınıfı hem “A.cs” sınıfından hem de “B.cs” sınıfından kalıtım alsın ve ikisininde elemanlarını kullansın.
Bu işlemi yapabilmek için, fonksiyonel olarak genişletilebilme özelliğine sahip “Extension Method” yapılarını kullanacağız.”A.cs” ve “B.cs” sınıflarında kullanmak istediğimiz metodları interface yapılarına Extension metod olarak uygulayarak bu işin içinden çıkabiliriz.
Şimdi “IA.cs” ve “IB.cs” isimli iki interface oluşturuyorum.
interface IA { }
interface IB { }
Şimdi de Extension metodlarımızı yazacağımız sınıfımı oluşturuyorum.
static class Extension { public static string AdSoyad(this IA nesne) { return "Gençay Yıldız"; } public static string Memleket(this IB nesne) { return "Artvin"; } }
Gördüğünüz gibi “AdSoyad” ve “Memleket” isimli metodları kendi sınıflarından çıkarıp “Extension”(sizler bu sınıfa istediğiniz gibi isim verebilirsiniz) isimli sınıfımda Extension metod olarak uyguluyorum.Yukarıda da bahsettiğim gibi bu metodları kendi sınıflarından çıkardıktan sonra interface yapısına sahip Extension metod haline getirdim.Burada interface yapılarımız bizim oluşturduğumuz “IA.cs” ve “IB.cs” isimli interface yapılarıdır.
Extension metod yapısı gereği hangi tipe özelse o tipte ve o tipten kalıtım alan sınıf ve interfacelerde kullanılmaktadır.
Hmmm madem bu özelliği biliyoruz, ona göre sanatımızı icra edebiliriz…
Şimdi “C.cs” isimli sınıfımı “IA.cs” ve “IB.cs” isimli sınıflardan türetirsem eğer(ki IA.cs ve IB.cs artık bir interface olduğu için çoklı kalıtım yapmış oluyoruz) yukarıda yazmış olduğumuz Extension metodlarımızada “C.cs” isimli sınıfımızdan ulaşabiliriz demektir.Yani dolaylı yoldan bir sınıfı birden fazla sınıftan türetme özelliği göstermiş olacağız…
class C : IA, IB { }
Şimdi “C.cs” sınıfımızdan bir örnek alıp çoklu kalıtım olayını yapabilmişmiyiz bakalım.
Gördüğünüz gibi “C.cs” sınıfımızın nesnesinde metodlarımız gözükmektedir.
Bakalım çalışıyorlar mı?
Gördüğünüz gibi tüm yapılar sapa sağlam çalışmaktadır.
Bu tekniğin içinde interface olması, interface yapılarından çoklu kalıtım alma olayıyla karıştırılmamalıdır.Bir sınıf bir ve ya birden fazla interface’den kalıtım alırken tüm elemanları implement etmek zorunda kalıyoruz.Lakin bu teknikte interfaceler sayesinde elemanları implement etme sorumluluğu gibi derdimiz olmadan istediğimiz metodu sınıfımıza kalıtım aracılığıyla kazandırıyoruz.
Burada dikkat etmeniz gereken husus sadece metodlarda bu tekniği kullanabiliyor olmamızdır.Property gibi elemanlar bu teknik dışında kalmaktadır.
Bu fikri bizlere sunan ve bu yazıya 4 yıl önceki makalesiyle destek vermiş olan sevgili Burak Selim Şenyurt hocamıza teşekkürlerimi sunarım…
Asıl bilgi ve kaynak için : http://www.buraksenyurt.com/post/Diamond-Problem-C-ve-Multiple-Inheritance.aspx adresini ziyaret edebilirsiniz.
İyi çalışmalar diliyorum…
Sonraki yazılarımda görüşmek dileğiyle…