Merhaba,
Ne zamandır inceleyip bir yazı yazmak istiyordum bu konuda. Gelelim konumuza. ILGenerator'la geliştirme yapmaya ne zaman ihtiyacımız olur onun net bir cevabı yok aslında ama birçok kullanım yeri olduğunu biliyorum. Ben örnek olması açısından "Merhaba Dünya" tarzında birşeyler yapacağım. Aşağıdaki kodu inceleyelim:
class Program
{
public delegate void Write(String str);
static void Main(string[] args)
{
DynamicMethod methodWrite = new DynamicMethod("Write", null, new Type[] { typeof(String) });
ILGenerator il = methodWrite.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Merhaba ");
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[]{typeof(String), typeof(String)}));
il.Emit(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new Type[]{typeof(string)}));
il.Emit(OpCodes.Ret);
Write writer = (Write)methodWrite.CreateDelegate(typeof(Write));
writer("Mehmet");
}
}
Yazdığım kod bildiğimiz bir console uygulamasına ait bir kod. Öncelikle delegate tanımına dikkat etmek lazım. Burda içi olmayan bir metod tanımı yapıyoruz. C++ 'taki fonksiyon pointer'i gibi düşünebiliriz. Daha sonra main metodunun içinde DynamicMethod oluşturup, ILGenerator ile metodun içini yazıyoruz.
Metodun içini yazarken sırasıyla yaptıklarımız şunlar:
1. Metod için oluşturulan stack alana "Merhaba" değerini ekliyoruz.
2. Stack alana 0.parametrede gelen değeri ekliyoruz.
3. String.Concat metodonu çağırıyoruz. Bu metod stack alandaki en son 2 değeri alıp string olarak birleştirdikten sonra çıkan sonucu da stack alana ekler. Bu işlemden sonra stackteki ilk iki değer silinmiş sadece yeni değer eklenmiş olur.
4. System.Concole.WriteLine(String) metodunu çağırıyoruz. Bu metod stack alandaki en son değeri ekrana yazdırır.
5. Son olarak metoda return ekliyoruz.
Böylece metodumuz oluşmuş oluyor. Sonra oluşturdumuz bu dinamik metodu Write delegasyon metoduna atıyoruz. Böylece metodumuz çalıştırılmaya hazır. Son satırda ise metodu çağırıyoruz.
Burada gözden kaçmaması gereken durum kodun tamamen runtime'da yazılıp derlenip çalıştırılıyor olmasıdır. Kompleks kodlar yazmak gerektiğinde ve özellikle performans beklenen yerlerde ILGenerator ile çok başarılı işler yapılabilir.
Aşağıda da yine iki sayıyı toplayan bir metodun dinamik olarak yazımı var:
class Program
{
public delegate int Sum(int a, int b);
static void Main(string[] args)
{
DynamicMethod methodSum = new DynamicMethod("Sum", typeof(int), new Type[] { typeof(int), typeof(int) });
ILGenerator il = methodSum.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // Stack Durumu : 3
il.Emit(OpCodes.Ldarg_1); // Stack Durumu : 3, 5
il.Emit(OpCodes.Add); // Stack Durumu : 8
il.Emit(OpCodes.Ret);
Sum summer = (Sum)methodSum.CreateDelegate(typeof(Sum));
int result = summer(3, 5);
}
}