C#’ta System.Reflection Kütüphanesi
Merhaba,
C# dilinde; bir sınıfın elemanlarına nesne, referans yahut sınıf ismi üzerinden erişmekten ziyade alternatif bir şekilde programatik olarak erişebilmek için ilgili tipin üzerinde belli adımlarla çalışma gerçekleştirmemiz gerekmektedir. İşte bu adımların kaynağını bizlere System.Reflection kütüphanesi sağlamaktadır.
Aslında bilinen bir tip üzerinde reflect işleminin her ne kadar önemi olmasada, bilinmeyen, özelleştirilmiş(generic) çalışmalarda elde edilen nesnelerin memberlarına erişilmesi gereken bir durumda kullanacağımız birinci dereceden önem arz eden bir yapıdan bahsediyor olacağız.
Şimdi konuyu pratikle destekleyerek ilerlemeye başlayabiliriz. Aşağıdaki sınıf örnek bir Reflection işlemi için hazırlanmıştır.
class Ogrenci { public string OgrenciNo { get; set; } public string Adi { get; set; } public string SoyAdi { get; set; } public double MaasHesapla(int Saat, double Ucret) => Saat * Ucret; }
Aslında bu sınıfın tipi, içeriği ve tüm elemanları net bir şekilde belli olmasına karşın reflect işleminin uygulanmasında bir girizgah olması açısından aşağıdaki gibi System.Reflection kütüphanesinin nimetlerinden yararlanarak mevcut elemanlarına erişebiliriz.
Gördüğünüz gibi ilgili tip üzerinden(ki bu tip bir referans yahut nesne üzerinden GetType metodu ilede görüldüğü gibi elde edilebilir) “Get” ile başlayan metodların çoğunu kullanarak reflect işlemlerini gerçekleştirebiliriz. Mesela bu metodlardan “GetProperties” metodu ilgili tip içerisindeki property yapılarına getirirken, “GetMethods” metodu ise tip içerisinde mevcut olan metodları elde ettirmektedir. Ve bu işlemleri yaparken yapısına göre sınıflarda çalışmaktadır.(MethodInfo, PropertyInfo)
class Program { static void Main(string[] args) { Ogrenci o = new Ogrenci(); o.GetType().GetProperties().ToList().ForEach(p => { Console.WriteLine(p.Name); }); Console.Read(); } }
Yukarıdaki örnek kod bloğunu incelerseniz eğer, “Ogrenci” sınıfı içerisindeki tüm propertyleri elde ederek bunların isimlerini ekrana yazdırmış bulunmaktayız.
class Program { static void Main(string[] args) { Ogrenci o = new Ogrenci(); o.GetType().GetMethods().ToList().ForEach(m => { if (m.Name == "MaasHesapla") { var Sonuc = m.Invoke(o, new object[] { 3, 5 }); Console.WriteLine(Sonuc); } }); Console.Read(); } }
Bu örneğimizde ise “Ogrenci” sınıfı içerisindeki tüm metodları elde edip “MaasHesapla” isimli metodu Invoke metodu ile çalıştırmakta ve sonucu elde etmekteyiz. Burada dikkat etmeniz gereken nokta, elemanların adı, niteliği gibi özellikler dışında işlevselliği bir nesne gerektireceğinden dolayı Invoke metodunun ilk parametresine “o” referansındaki nesneyi vermekteyiz. Eee haliyle “MaasHesapla” metodu “o” referansına bağlı nesne üzerinden çalıştırılmış olacaktır.
Haliyle propertylerde de aynı mantık söz konusu olacaktır.
class Program { static void Main(string[] args) { Ogrenci o = new Ogrenci(); o.GetType().GetProperties().ToList().ForEach(p => { if (p.Name == "OgrenciNo") p.SetValue(o, "11040355"); else if (p.Name == "Adi") p.SetValue(o, "Gençay"); else p.SetValue(o, "Yıldız"); }); Console.WriteLine($"{o.Adi} {o.SoyAdi} {o.OgrenciNo}"); Console.Read(); } }
Gördüğünüz gibi propertylerede veri eklemek için bir nesneye ihtiyaç olacağından dolayı tekrar “o” referansındaki nesne SetValue metoduna bağlanmış ve o nesne üzerinden property çalıştırılmıştır.
Aynı işlem propertydeki veri çağrılırkende yapılmaktadır.
class Program { static void Main(string[] args) { Ogrenci o = new Ogrenci() { Adi = "Gençay", SoyAdi = "Yıldız", OgrenciNo = "11040355" }; o.GetType().GetProperties().ToList().ForEach(p => { if (p.Name == "OgrenciNo") Console.WriteLine($"Öğrenci No : " + p.GetValue(o)); else if (p.Name == "Adi") Console.WriteLine($"Adı : " + p.GetValue(o)); else Console.WriteLine($"Soyadı : " + p.GetValue(o)); }); Console.Read(); } }
Gördüğünüz gibi GetValue metodu işlevsel özellikte olduğu için “o” referansına bağlı nesne üzerinden değer çağrım işlemi gerçekleştirecektir.
Evet, buraya kadar Reflection işlemini bilinen bir class üzerinde uygulamış olduk.
Peki üzerinde çalıştığımız sınıf generic(özelleştirilmiş) ise ne yapacağız?
Tabi ki de aynı işlemleri uygulayacağız. Sadece olay biraz kompleksleş(miş) gibi gözükecektir.
Hele hele elimizdeki sınıf Generic Extension metod barındıyorsa?
İşte bu soruya özel olarak tasarladığım aşağıdaki örnek kod bloğunu inceleyiniz.
static class Islemler { static public T Islem<T>(this T nesne, T yeniNesne) where T : class, new() { nesne.GetType().GetProperties().ToList().ForEach(p => { yeniNesne.GetType().GetProperties().ToList().ForEach(p2 => { if (p.Name == p2.Name) { p.SetValue(nesne, p2.GetValue(yeniNesne)); } }); }); return nesne; } static public T Islem<T>(this T nesne) where T : class, new() { T yeniNesne = new T(); nesne.GetType().GetProperties().ToList().ForEach(p => { p.SetValue(yeniNesne, "sdasd"); }); return yeniNesne; } }
Burada görüldüğü üzere Islem adında iki adet overload generic extension metod tasarlanmıştır. Bu metodlar içerisinde üzerinde çalışılan nesnenin propertyleri elde edilmektedir. Tek parametreli metod elde ettiği propertye manuel değer vermektedir. Burada dikkat etmemiz gereken nokta, içerisinde T tipinde oluşturulan bir nesne, SetValue metodunda fiziksel kaynak olarak kullanılmaktadır. Diğer metodumuz ise üzerinde çalıştığı nesne ile ikinci parametrede aldığı nesnenin benzer propertylerini kontrol etmekte ve ilgili nesneye, parametreyle alınan nesnenin değerleri set edilmektedir.
Son olarak System.Reflection kütüphanesinin önemini özetleyen bir sözle içeriğimizi sonlandırmak istiyorum;
“Bir şeyi çözemiyorsan onun çözümü kesinlikle Reflection’dır.”
Okuduğunuz için teşekkür ederim…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…
size beton yetmez be hocam biliyorsunuz değil mi
🙂
Hocam makale için teşekkür ederiz. Biraz daha örneklendirebilirseniz ya da video gelirse harika olur.
Hocam kolay anlatiminiz icin size cok minnetdarim!