C Sharp Programlama Dili/Yansıma
Geçen derste assembly kavramını ve assemblylerle kullanılan bazı sınıfları incelemiştik. Şimdi ise bir assemblydeki tür ve üye eleman bilgilerini çalışma zamanında elde etmek demek olan yansıma konusunu inceleyeceğiz. Konumuza tam giriş yapmadan önce bir operatör ve bir metodu tanıtmak istiyorum:
- typeof() operatörü herhangi bir türü System.Type türüne çevirip tutar. Örnek:
Type a=typeof(int);
- GetType() metodu herhangi bir nesnenin türünü Type türünden tutar. static değildir. object sınıfının bir metodudur. Dolayısıyla bütün türlere kalıtım yoluyla geçmiştir. Örnek:
int a;
Console.WriteLine(a.GetType());
Bu kod ekrana System.Int32 yazacaktır. Şimdi esas konumuza başlayabiliriz.
Type sınıfı
değiştirType sınıfı System isim alanında bulunan özet (abstract) bir sınıftır. Dolayısıyla
Type t=new Type();
gibi bir ifade mümkün değildir. Type türünden nesneler belirli bir türü temsil ederler. Type sınıfındaki static olmayan IsClass, IsAbstract, IsEnum, IsInterface, IsNotPublic, IsPublic, IsSealed ve IsValueType özellikleri vardır. Bunlar aşağıdaki koşullar sağlanıyorsa true, sağlanmıyorsa false değer döndürür:
IsClass → İlgili tür sınıfsa
IsAbstract → İlgili tür özetse
IsEnum → İlgili tür enumsa
IsInterface → İlgili tür arayüzse
IsNotPublic → İlgili tür public değilse
IsPublic → İlgili tür publicse
IsSealed → İlgili tür sealed ise
IsValuType → İlgili tür yönetilmeyen tür ise
Ayrıca Type sınıfının static olmayan IsAssignableFrom(Type tür) metodu parametredeki tür nesnesinin ilgili tür nesnesine atanıp atanamayacağının anlaşılması için kullanılır. Atanabiliyorsa true, atanamıyorsa false değer döndürür. Örnek:
//yavru sınıfının ana sınıfından türediğini varsayalım.
Type a=typeof(ana);
Type y=typeof(yavru);
Console.WriteLine(a.IsAssignableFrom(y));
Console.WriteLine(y.IsAssignableFrom(a));
Bu kod alt alta True ve False yazacaktır.
MemberInfo sınıfı
değiştirBir türdeki üye elemanları temsil etmek için kullanılır. Özet bir sınıftır, dolayısıyla new operatörüyle yeni MemberInfo nesnesi tanımlanamaz. MemberInfo sınıfının önemli özellikleri:
- Type DeclaringType İlgili üye elemanın içinde bulunduğu türü Type türünden döndürür.
- MemberTypes MemberType İlgili üye elemanın ne tür bir eleman olduğunu MemberTypes enumu türünden döndürür. MemberTypes enumu Constructor, Method, Event, Field ve Property sözcüklerini içerir. Bunlar şu anlamlara gelir:
- Constructor → yapıcı metot
- Method → metot
- Event → olay
- Field → özellik
- Property → sahte özellik
- string Name ilgili üye elemanın ismini string olarak verir.
Type sınıfının GetMembers() metodu kullanılarak bir türdeki bütün üye elemanlar MemberInfo türünden bir diziye aktarılır. Ayrıca yine Type sınıfının GetMember(string eleman) metodu, ismi belirtilen string olan üye elemanları bir MemberInfo dizisi olarak döndürür. Örnek bir program:
using System;
using System.Reflection;
class deneme
{
static void Main()
{
Type t=typeof(string);
MemberInfo[] elemanlar=t.GetMembers();
foreach(MemberInfo mi in elemanlar)
{
if(mi.MemberType==MemberTypes.Method)
Console.WriteLine(mi.Name);
}
}
}
Bu program String sınıfındaki tüm metotları ekrana yazacaktır.
MethodInfo sınıfı
değiştirTürlerdeki metotları temsil etmek için kullanılan bir sınıftır. Bu sınıf MemberInfo sınıfından türemiş olan MethodBase sınıfından türemiştir. Dolayısıyla MemberInfo sınıfındaki tüm üye elemanları taşır. Bu sınıfta ek olarak metotların geri dönüş tipini Type türünden döndüren ReturnType özelliği ve metotların parametrelerini ParameterInfo sınıfı türünden bir dizi olarak döndüren GetParameters() metodu da bu sınıfta bulunan üye elemanlardandır. Type sınıfının GetMethods() metodu bir türdeki tüm metotları bir MethodInfo sınıfı dizisi türünden döndürür. Ayrıca Type sınıfının GetMethods(BindingFlags kriterler) metodu bir türdeki belirli kriterlere uyan metotları bir MethodInfo dizisi olarak döndürür. BindingFlags System.Reflection isim alanındaki bir enumdur. BindingFlags enumundaki önemli sözcükler:
- DeclaredOnly → Yalnızca ilgili türün kendi metotları diziye aktarılır. Kalıtım yoluyla gelenler aktarılmaz.
- NonPublic → public olarak işaretlenmemiş metotlar
- Public → public olarak işaretlenmiş metotlar
- Static → static olarak işaretlenmiş metotlar
- Type sınıfının GetMethod(string metotismi) metodu ilgili türdeki stringte verilen metodu MethodInfo türünden döndürür.
- MethodInfo sınıfındaki IsStatic özelliği ilgili metot staticse true değilse false değer döndürür. Örnek program:
using System;
using System.Reflection;
class Yansima
{
static void Main()
{
Type t=typeof(Array);
MethodInfo[] metotlar=t.GetMethods();
foreach(MethodInfo mi in metotlar)
{
Console.WriteLine("Metot ismi: "+mi.Name);
Console.WriteLine("Geri dönüş tipi: "+mi.ReturnType);
Console.WriteLine(mi.IsStatic?"Static":"Static değil");
}
Console.WriteLine("Toplam metot: "+metotlar.Length);
}
}
Farkındaysanız programımızda çok önceden gördüğümüz ?: operatörünü kullandık. Bu operatör if ile 3-4 satırda yazabileceğimiz kodu tek satıra indirdi. Başka bir örnek:
using System;
using System.Reflection;
class Yansima
{
static void Main()
{
AppDomain ad=AppDomain.CurrentDomain;
Assembly[] assembly=ad.GetAssemblies();
Type[] tipler=assembly[0].GetTypes();
foreach(Type tip in tipler)
{
Console.WriteLine("Tip: "+tip.Name);
Console.WriteLine("Metot sayısı: "+tip.GetMethods().Length);
Console.WriteLine();
}
}
}
MethodInfo sınıfının IsStatic özelliği yanında IsAbstract, IsConstructor, IsPublic, IsPrivate, IsVirtual özellikleri de mevcuttur.
ParameterInfo sınıfı
değiştirMetotların parametreleriyle ilgilenen bir sınıftır. Bir metodun parametrelerini elde etmek için MethodInfo sınıfının GetParameters() metodu kullanılabilir. MethodInfo sınıfının GetParameters() metodu bir ParameterInfo dizisi döndürür. ParameterInfo sınıfının ParameterType özelliği ilgili parametrenin türünü Type türünden döndürür. Yine ParameterInfo sınıfının Name özelliği ilgili parametrenin ismini string olarak döndürür.
ConstructorInfo sınıfı
değiştirBir türün yapıcı metoduyla ilgilenir. Type sınıfının GetConstructors() metodu bu sınıf türünden bir dizi döndürür. Bu sınıfa ait en önemli metot GetParameters() tır. ParameterInfo sınıfı türünden bir dizi döndürür.
PropertyInfo, FieldInfo ve EventInfo sınıfları
değiştirBu sınıflar sırasıyla bir türdeki sahte özellikler, normal özellikler ve olaylarla ilgilenir. Type sınıfının GetProperties(), GetFields() ve GetEvents() metotları bu sınıflar türünden dizi döndürürler. Her üç sınıfta da Name özelliği mevcuttur. EventInfo sınıfının şu önemli özellikleri mevcuttur.
- IsMulticast → Olayın multicast olup olmadığını verir.
- EventHandlerType → Olayın türünü RuntimeType türünden verir. (Bir temsilci)
NOT: Type sınıfının GetMethods(), GetProperties() gibi metotları yalnızca public üye elemanları döndürür.
NOT: Gördüğümüz MethodInfo, EventInfo gibi sınıfların tamamı System.Reflection isim alanındadır. Yalnızca Type System isim alanındadır. Yine konuyu işlerken karşımıza çıkan enumlar da System.Reflection isim alanındadır.
Çalışma zamanında metot çağırma
değiştirŞimdiye kadar metotlarımızı derleme zamanında çağırdık. Ancak artık System.Reflection isim alanındaki sınıflar sayesinde metotlarımızı çalışma zamanında çağırabileceğiz. Bunun için MethodInfo ve ConstructorInfo sınıflarında bulunan
object Invoke(object nesne,object[] parametreler)
metodunu kullanacağız. Eğer ConstructorInfo sınıfındaki metodu çağırırsak çalışma zamanında nesne oluşturmuş oluruz. Invoke() metodunun birinci parametresi metodun hangi nesne üzerinden çağrılacağını belirtir. İkinci parametre ise çağrılacak metoda verilecek parametreleri içeren object tipinden bir dizidir. Çalışma zamanında çağrılacak metot static ise birinci parametre null olmalıdır. Benzer şekilde çağrılacak metot parametre almıyorsa ikinci parametre null olmalıdır. Programımız şu şekilde:
using System;
using System.Reflection;
class Deneme
{
public static int Topla(int a, int b)
{
return a+b;
}
}
class Ana
{
static void Main()
{
object[] parametreler={9,5};
int a=(int)MetotInvoke("Topla","Deneme",parametreler);
Console.WriteLine(a);
}
static object MetotInvoke(string metot,string tip,object[] args) //tip ile metodun hangi türün içinde olduğunu anlıyoruz.
{
Type t=Type.GetType(tip); //Aldığımız string hâlindeki tipi Type türüne dönüştürüyoruz.
if(t==null)
throw new Exception("Tür bulunamadı");
MethodInfo m=t.GetMethod(metot); //Aldığımız string hâlindeki metodu MethodInfo türüne dönüştürüyoruz.
if(m==null)
throw new Exception("Metot bulunamadı");
if(m.IsStatic)
return m.Invoke(null,args);
object o=Activator.CreateInstance(t);
return m.Invoke(o,args);
}
}
Bu program sonucunda ekrana 14 yazılacaktır. Burada MetotInvoke() metodu kendimizin oluşturduğu bir metottur. Kendiniz bu metoda farklı isimler verebilirsiniz. Bu metodun Invoke() metoduna iletilecek veriler için bir "ulak" vazifesi görmektedir. Yani bu metodun yaptığı tek iş Invoke() metoduna gerekli dönüşümleri yaparak ve gerekli hata durumlarını göz önünde bulundurrarak gerekli verileri iletmektir. Programın kritik satırları şunlardır:
if(m.IsStatic)
return m.Invoke(null,args);
object o=Activator.CreateInstance(t);
return m.Invoke(o,args);
Birinci ve ikinci satırda çalıştırılmak istenen metodun static mi değil mi olduğu kontrol ediliyor. Eğer staticse metoda herhangi bir nesne üzerinden erişilmiyor. Üçüncü satırda System isim alanındaki Activator sınıfındaki CreateInstance() metoduyla yeni bir nesne oluşturuluyor. Bu metot parametre olarak nesnenin hangi türden oluşturulacağını belirten Type türden bir tür alır. Son satırda ise oluşturulan söz konusu nesneyle ve parametrelerle metot çağrılıyor.