ILGenerator ile Dynamic Method

Şubat 14, 2012 at 11:32 mehmet.baran

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"nullnew 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);                      
    }
}      

 

Posted in: .Net

Tags: , , ,

DesingMode Hatalarına Önlem

Şubat 7, 2012 at 4:28 mehmet.baran

Merhaba,

Visual Studio'da, Windows Form uygulamaları geliştirirken bazen design mode 'da ekranı açarken hatalar alabiliyoruz. Bunun sebebi design mode dahi olsa aslında ekran kodlarınızın visual studio tarafından çalıştırılıyor olması. Örneğin form veya bir controlün constructor kısmında veri tabanına bağlanma, web servis çağrısı, dosya okuma-yazma gibi hata alması muhtemel kod blokları çalışıyor ise ekranı design mode'da açamamanız mümkün. 

Bu tür hataların önüne geçmek için kod bloklarının design time'da çalışmasını engelleyebiliriz.

if(DesignMode) // Component.DesignMode
{
    return;
}

şeklinde bir kod parçası ile design mode hataların önüne geçebiliriz.

Fakat contructorda yazılan kod bloklarında henüz controle ait tüm bileşenler hazır olmadığı için DesignMode property'si her durumda false dönecektir. Bunun için de 

if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) 
{
    return;
}

şeklinde bir kontrol ifadesi kullanabiliriz. 

 

Posted in: .Net | Windows Forms

Tags: , ,