Reflection nedir?

0 dakikada yazıldı

53286 defa okundu

Düzenle

Başlık olarak “Reflection” yazdıktan sonra ardına sayfalarca
açıklama ve örnek konulabilir. Hatta bu konuda ayrı bir kitap bile
yazılabilir. Reflection’ın çok farklı kullanımlar var. Özetleyerek hızlı
bir şekilde tanımlamak istersek aslında Reflection bize hakkında bilgi
sahibi olmadığınız programatik nesnelerle ilgili çalışma zamanında
(run-time) bilgi alabilmemize olanak tanıyan bir metottur. Peki böyle
bir şeye neden ihtiyacımız olsun? En basit örnek gerçek zamanlı olarak
uygulamalara farklı DLL dosyalarının bağlandığı durumları
gösterebiliriz. Böyle bir durumda kaynak konumdaki sınıflar veya
metotlar ile ilgili herhangi bir bilgi bulunmaz. Söz konusu bu
bilgilerin program çalışırken elde edilerek kullanılması gerekir. Gelin
ilk olarak Reflection’ın yapısını ve sistemini tanımak adına tek bir
uygulama içerisinde nasıl kullanılabileceğimize göz atalım. Örnek
uygulamamızda aşağıdaki şekli ile tanımlanmış bir Urun sınıfı
kullanacağız.

[VB]

Public Class Urun

 

    Private PAdi As String

    Public Property Adi() As String

        Get

            Return PAdi

        End Get

        Set(ByVal value As String)

            PAdi = value

        End Set

    End Property

 

    Sub New()

 

    End Sub

 

    Sub New(ByVal
adi As String)

        Me.Adi = adi

    End Sub

 

    Function Uyari() As String

        Return "Ürünün adı: " & Me.Adi

    End Function

End Class

[C#]

public class Urun

{

 

    private string PAdi;

    public string Adi

    {

        get { return PAdi; }

        set { PAdi = value; }

    }

 

    public Urun()

    {

 

    }

 

    public Urun(string adi)

    {

        this.Adi = adi;

    }

 

    public string Uyari()

    {

        return "Ürünün adı: " + this.Adi;

    }

}

Uygulamamız içerisinde iki adet düğme yer alacak ve kullanacağımız
Windows penceresinde global olarak tanımlanmış bir de Object tipinde
değişkenimiz bulunacak.

[VB]

Dim BirUrun As Object   

[C#]

object BirUrun;

Uygulama içerisindeki düğmelerden birine basıldığında global BirUrun
değişkenimiz yeni bir Urun değişkenine dönüştürülecek.

[VB]

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles
Button1.Click

    BirUrun = New Urun

End Sub

[C#]

    private void button1_Click_1(object sender, EventArgs e)

    {

        BirUrun = new Urun();

    }

Programımız içerisinde diğer düğmeye basıldığında BirUrun adındaki
değişkenimizin Adi özelliğini değiştirerek Uyari adındaki
metodunu kullanmak istiyoruz. Fakat Visual Studio içerisinde maalesef ki
BirUrun adındaki değişkenle beraber Urun tipine ait Intellisense
desteği gelmeyecektir. Aslında bu durumun haklı bir nedeni var. İkinci
düğmeye basıldığında BirUrun adındaki değişkenin tipininin
Object mi yoksa Urun mü olacağı belli değil. İşte tam da
istediğimiz ortamı yaratmış olduk. Kullanacağımız nesnenin tipi belirsiz
ve biz ona ait bazı özellikleri kullanmak istiyoruz. Bu durumda ilk
olarak ikinci düğmeye basıldığında gerçekten BirUrun değişkeninin
tipi Urun mü yoksa değil mi sorusunu kontrol etmemiz lazım.

[VB]

       If TypeOf (BirUrun) Is Urun Then

 

        End If

[C#]

        if ((BirUrun) is Urun)

        {

 

        }

Buraya kadar her şey çok kolay. Bundan sonra eğer IF kontrollerimize
olumlu sonuç dönüyorsa ilk olarak gidip nesnenin Adi özelliğini
bulmamız ve ona bir değer aktarmamız gerekiyor.

[VB]

BirUrun.GetType.GetProperty("Adi").SetValue(BirUrun, "Daron", Nothing)

[C#]

BirUrun.GetType().GetProperty("Adi").SetValue(BirUrun, "Daron", null);   

Yukarıdaki kod ile elimizdeki nesnenin tipini bilmeden onun Adi
adındaki özelliğini (property) yakalayarak değerini Daron olarak
değiştiriyoruz. Kodumuzu detaylı olarak adım adım bakacak olursak ilk
aşamada nesnenin tipini GetType ile alıyoruz. Sonrasında ise tipini
yakaladığımız nesnenin GetProperty ile Adi adındaki özelliğini
alarak SetValue ile söz konusu özelliğin değerini değiştiriyoruz.
SetValue metodu toplam üç parametre alıyor; bunlardan ilki değer
değişikliği yapılacak nesnenin kendisi, ikincisi yeni atanacak olan
değer, üçüncüsü ise eğer değiştirilecek olan özellik (property)
indeksli ise söz konusu indeks değeri. Bizim örneğimizde indeksli bir
özellik olmadığı için bu parametreyi boş geçiyoruz.

Değer atamamızı tamamladığımıza göre bu sefer de sıra geldi BirUrun
değişkenimize ait Uyari metodunu çalıştırmaya. Metodumuz bize bir
String döndürecek biz de onu doğrudan bir mesaj kutusu ile
kullanıcıya göstereceğiz.

[VB]

BirUrun.GetType.InvokeMember("Uyari",
Reflection.BindingFlags.InvokeMethod, Nothing, BirUrun, Nothing)

[C#]

BirUrun.GetType().InvokeMember("Uyari",
System.Reflection.BindingFlags.InvokeMethod, null, BirUrun, null).ToString();

Reflection kullanarak türü bilinmeyen bir nesnenin bir metodunu
çalıştırmak için InvokeMember metodundan faydalanmamız gerekiyor.
InvokeMember aslında çok geniş kullanımı olan bir metod, biz
şimdilik sadece bir çeşit kullanımına değineceğiz. Örneğimizde
InvokeMember bir metod çalıştıracağı için ilk parametresinde
çalıştırılacak olan metodun adını ikincisinde
BindingFlags.InvokeMethod ile bir Metod çalıştırılacağını
belirtiyoruz. Üçüncü parametre bizim şimdilik kullanım alanımız dışında
kalan Binding’lerle ilgili, aynı şekilde beşinci parametre de boş
bırakılarak geçilecek. Dördüncü parametrede ise hedef nesnemiz olan
BirUrun değişkenimizi atayacağız. Böylece metodumuzu da çalıştırmış
olduk.

Dinamik DLL Kullanımı

Kabaca Reflection’ın nasıl kullanılabildiğine dair bir örnek yaptıktan
sonra artık sıra geldi harici bir DLL dosyasının çalışma anında
programımıza ekleyerek içerisindeki yapıları kullanmaya. Bu çeşit bir
işlevselliği özellikle gerçek zamanlı DLL derlemesi ile
birleştirdiğinizde çok farklı bir dünyaya kapı açmış olacaksınız. Hedef
olarak kullanacağımız DLL dosyasını aşağıdaki kodlardan yaratacağız.

[VB]

Public Class Deneme

    Function Metin() As String

        Return "Çalışıyor"

    End Function

End Class

[C#]

    public class Deneme

    {

        string Metin()

        {

            return "Çalışıyor";

        }

Yarattığımız DLL dosyasını uygulamamız ile aynı konuma yerleştirdikten
sonra aşağıdaki kod ile DLL’imizi kullanmaya başlayabiliyoruz.

[VB]

Dim BirAssembly As Reflection.Assembly =
Reflection.Assembly.LoadFrom("ornek2.dll")

[C#]

System.Reflection.Assembly BirAssembly =
System.Reflection.Assembly.LoadFrom("ornek2.dll");

Artık yukarıda tanımladığımız Assembly üzerinden Reflection
kullanarak ilerleyebiliriz. İlk olarak Deneme adında sınıfımızdan
bir instance almamız gerekecek. Bunun için Deneme tipini
bulmamız lazım.

[VB / C#]

BirAssembly.GetModule("Ornek2.dll").GetType("Deneme")

Assembly üzerinden modülümüzü yakalıyor sonra da Deneme adındaki
tipinizi buluyoruz. Tabi tipi bulmak yeterli değil, söz konusu tipte bir
değişken yaratmamız gerekiyor. Activator sınıfını kullanarak bu tip
üzerinden bir instance yaratarak Sinif adında bir değişkene
aktaracağız.

[VB]

Dim Sinif =
Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"))   

[C#]

object Sinif =
Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"));

Yarattığımız sınıfın maalesef özellikleri otomatik olarak gelmeyecek. O
nedenle Metin adındaki metodumuzu da elle bularak çalıştırmak
zorundayız.

[VB]

BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, Nothing)

[C#]

BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, null)

Yine Assembly üzerinden yola çıkarak bu sefer daha da ileri
gidiyoruz. Deneme sınıfımızı bulduktan sonra içerisinde Metin
adındaki metodumuzu buluyor ve doğrudan Invoke ile söz konusu metodu
çalıştırıyoruz. Invoke metodu bizden iki parametre istiyor;
bunlardan ilki ana sınıfın kendisi. Bir önceki adımda yakaladığımız
sınıfı buraya parametre olarak aktarıyoruz. Diğeri ise bizim
kullanmayacağımız Binding parametresi.

Metin metodumuz çalıştırıldığında geriye bir String değişkeni
döndürüyor. Bu değişkeni de bir mesaj kutusu ile kullanıcıya göstermek
istersek uygulamamızın tam kodunun aşağıdaki şekilde sonlanması
gerekiyor.

[VB]

Public Class Form2

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles
Button1.Click

        Dim BirAssembly As Reflection.Assembly =
Reflection.Assembly.LoadFrom("ornek2.dll")

 

        Dim Sinif =
Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"))

        MsgBox(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, Nothing))

    End Sub

End Class

[C#]

namespace CSReflection

{

    public partial class Form2 : Form

    {

        public Form2()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            System.Reflection.Assembly BirAssembly =
System.Reflection.Assembly.LoadFrom("ornek2.dll");

 

            object Sinif =
Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"));

            MessageBox.Show(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, null).ToString());

        }

    }

}

Böylece harici bir DLL dosyasını yükleyerek istediğimiz metodu dinamik
olarak kullanabildik. Farklı durumlarda isterseniz bir DLL içerisinde
tüm metod, sınıf ve özelliklerin listelerini alabilir hatta bunları LINQ
sorguları ile tarayabilirsiniz.

[VB]

Dim Metodlar = From Gelenler In BirAssembly.GetModule("Ornek2.dll").GetTypes Where Gelenler.GetMethod("Metin") IsNot Nothing

[C#]

var Metodlar = from Gelenler in
BirAssembly.GetModule("Ornek2.dll").GetTypes() where
Gelenler.GetMethod("Metin") !=
null select Gelenler;

Örneğin yukarıdaki LINQ sorgumuz ile harici DLL dosyası içerisinde
Metin adında metodu olan tüm sınıfların bir listesini alıyoruz.

Hepinize kolay gelsin.