İlkay İlknur

just a developer...

Expando Object İçerisine Dinamik Olarak Member Ekleme

C# 4.0'daki dynamic yenilikleri ile beraber hayatımıza giren tiplerden biri de ExpandoObject. Bu tip ne işe yarıyor diye ufak bir hatırlatma yaparsak, ExpandoObject'in içerisine runtime'da dinamik olarak member eklenebiliyor. Örneğin,

class Program
{
    static void Main(string[] args)
    {
        dynamic d = new ExpandoObject();
        d.Foo = "foo";
        d.Bar = 4;

        Console.WriteLine("Foo=" + d.Foo);
        Console.WriteLine("Bar=" + d.Bar.ToString());
    }
}

Gördüğünüz gibi runtimeda Foo ve Bar fieldlarını ekledik ve sonrasında da bu fieldları ekrana yazdırdık. Buraya kadar olan kısmını zaten ExpandoObjecti biliyorsanız size yabancı gelmeyecektir.

ExpandoObject kullanırken oluşabilecek olan ihtiyaçlardan biri de ExpandoObject içerisine koyacağımız alanların runtimeda belirlenmesi olabilir. Yani üstteki örnekteki Foo ve Bar alanlarının isimlerinin ve valuelarının database'den geldiğini düşünün. Kodunuza göre bu alanların adı Foo ve Bar olabiliyorken aynı zamanda Ahmet ve Mehmet de olabilir. Bu tamamen databaseden gelecek sonuca bağlı. Bu durumda haliyle d.Foo veya d.Ahmet gibi birşey yapamıyoruz.  Çünkü ne geleceği belli değil. Peki burada nasıl ilerleyebiliriz ?

ExpandoObject'in tanımına bakarsınız IDictionary<string, object> interface'ini implemente ettiğini görürsünüz. Dolayısıyla bu da bize istediğimiz başarmamızın yollarını açıyor :)

class Program
{
    static void Main(string[] args)
    {
        dynamic d = new ExpandoObject();
        IDictionary<stringobject> members = d as IDictionary<stringobject>;
        members.Add("Foo""foo");
        members.Add("Bar", 4);

        Console.WriteLine("Foo=" + d.Foo);
        Console.WriteLine("Bar=" + d.Bar.ToString());
    }
}

Tabi yukarıda dictionary içerisine eklediğimiz alanların dinamik olarak bir yerlerden geldiğini(mesela databaseden yada bir API'dan) düşünmenizde fayda var :) Bu kullanım bahsettiğim gibi dinamik object içerisinde bulunacak olan alanların dışarıdan belirlendiği senaryolarda oldukça anlamlı ve kullanılabilir. Ufak ama lazım olduğunda hayat kurtaran bir nokta :)



Dynamic Language Runtime (DLR) Nedir ?

Merhaba,

.NET Framework 4.0'ın çıkmasıyla birlikte hayatımıza girecek en büyük yeniliklerden biri de dinamik programlama. Zaten C# programlama dilinin gelecek olan 4.0 versiyonunun teması da "Dinamik Programlama" olarak belirlenmiş durumda. Günümüzde baktığımızda dinamik programlama paradigması oldukça popüler durumda. Peki bu kadar popüler olmasının nedenleri neler öncelilkle bunlara bir gözatalım.
  • Herhangi bir tip seçiminin yapılmaması,
  • Derleme yapılmaması, yorumlama ile kodların çalıştırılması,
  • Tüm işlemlerin (tip atamalarının, tip bağlamalarının) çalışma zamanında yapılması,
  • Geliştiriminin kolay olması olarak söyleyebiliriz.
Ayrıca IronPython, IronRuby gibi dinamik programlama dilleri ile .NET altyapısını da kullanarak uygulamalarımızı daha hızlı ve etkin bir şekilde geliştirebilmekteyiz. .NET Framework 4.0 ile beraber ise artık bizler de dinamik işlemler yapabiliyor ve dinamik programlama dilleri ile konuşabiliyor olacağız. Bu yazımızda ise bizlere bu dinamik altyapıyı sunacak olan Dynamic Language Runtime (DLR) yapısını inceliyor olacağız.

Dynamic Language Runtime (DLR) Nedir ?

Dynamic Language Runtime temel olarak  IronPython,IronRuby gibi dinamik programlama dillerinin Common Language Runtime (CLR) ile iletişim kurmasını sağlayan aynı zamanda da C# ve VB gibi statik programlama dillerine de dinamik özellikler, yetenekler kazandıran bir altyapı sağlamaktadır. Dynamic Language Runtime içerisine baktığımızda ise karşımıza 4 temel yapıtaşı çıkmaktadır. Bunlar:
  • Expression Trees
  • Dynamic Dispatch
  • Call Site Caching
  • Binders
Bu yapıların hepsini teker teker incelersek,

Expression Trees 

Expression Trees yapısı aslında LINQ ile beraber .NET Framework içerisine eklenen bir yapıdır. Temel olarak yazılan kodların doğrudan direkt olarak MSIL'e çevrilmeden bir ağaç yapısında tutulmasını sağlamaktadır. Daha sonra bu ağaçlarda bulunan kodlar çalışma zamanında derlenerek yazılan kodların dinamik olarak çalıştırılması gerçekleşmektedir. Bu nedenle bu mekanizma DLR içerisinde de yoğun olarak kullanılmaktadır.

Dynamic Dispatch

Dynamic Dispatch yapısı ile çalışma zamanında dinamik metot çağırımlarına imkan sağlanmaktadır. Örneğin derleme zamanında hangi metodun çağırılacağının belli olmadığı durumlarda dynamic dispatch kullanılarak hangi metodun çağırılacağına karar verilmektedir.

Call Site Caching

DLR içerisinde bulunan en önemli yapılardan biri de Call Site Caching mekanizmasıdır. DLR'ın bu kadar etkin ve Reflection'a göre bu kadar hızlı çalışmasının en önemli nedeni olduğunu rahatlıkla söyleyebiliriz. Call Site Caching ile çalışma zamanı sırasında yapılan dinamik çağrımlar Call Site Cache içerisinde saklanmaktadır. Böylece uygulamanın çalışma evresi içerisinde yapılacak olan diğer çağrımlardan önce eğer cache içerisinde tutulmuş bilgi varsa doğrudan bu bilgi kullanılarak kod daha hızlı olarak çalıştırılmaktadır. Oysaki daha önce kullandığımız reflection mekanizmalarında bizim yazdığımız tüm reflection işlemleri kodun her çağrımında defalarca yapılmaktadır.

Binders

DLR içerisinde DLR'ın iletişim kurabildiği platformlar ile ilgili tüm bilgilere sahip olan Binder yapıları bulunmakta. Binder yapısı üst taraftaki yazılan kodun alt tarafta bulunan platformlarda nasıl çalıştırılacağı (bind edileceği) ile ilgili tüm bilgileri taşımaktadır ve gerektiğinde de ilgili işlemleri gerçekleştirmektedir. Yazılan dinamik bir kodun çalışmasını kısaca özetlersek: Dinamik bir çağrım yapılmadan önce bu çağırımla ilgili daha önce yapılıp yapılmadığıyla ilgili bilgi edinmek için Call Site Cache'e bakılır. Eğer bilgi bulunursa direkt olarak buradan kod çalıştırılır. Ancak herhangi bir bilgi bulunamazsa altyapıdaki ilgili binder kullanılarak kod çalıştırılır ve gerekli bilgiler ileride kullanılmak amacıyla Call Site Cache'e eklenir. Dynamic Language Runtime ile ilgili değinmemiz gereken önemli noktalardan biri de DLR'ın doğrudan ve sadece Microsoft tarafından geliştirilmediği. Aslında DLR Microsoft ve topluluklar ile beraber geliştirilmekte olan bir topluluk projesi. DLR'ın bir kısmının doğrudan .NET Framework içerisine gömülü olmasına rağmen özellikle ileriki yazılarımda bahsedeceğim Script Hosting ile ilgili kütüphaneler IronPython, IronRuby dillerini geliştiren topluluklar tarafından geliştirilmektedir. DLR'ın alt kısmında ise oldukça heyecan verici mekanizmalar bulunmakta. Özellikle Silverlight tarafında bulunan JavascriptBinder ile yazacağınız Javascript kodlarını artık doğrudan C# içerisinden yazabiliyorsunuz.  JavascriptBinder'ın kullanımından da ilerleyen günlerde bahsediyor olacağım. İyi geceler Smile


Dynamic Language Runtime - Silverlight Javascript Binder Mekanizması

Merhabalar,

Bu yazımda Dynamic Language Runtime içerisinde bulunan ve Silverlight platformu ile beraber kullanılan Javascript Binder mekanizmasından bahsedeceğim. Bir önceki yazımda da bahsettiğim gibi Dynamic Language Runtime içerisinde birçok farklı binder mekanizmaları bulunmakta. Binderlar, yapılan dinamik çağrımların altlarındaki platformlarda çalışması için gereken bilgiye sahipler ve bu bilgileri kullanarak bu dinamik çağırımları gerçekleştirirler.

Javascript Binder ne iş yapar ?

Javascript Binder kısaca Silverlight tarafında yapılabilecek olan Javascript işlemlerini C# tarafında yapabilmemize olanak sağlar.

Javascript Binder'dan önce ne yapıyorduk ?

DLR olmadan önce Silverlight tarafından javascript tarafında bulunan herhangi bir metodu çağıracağımız zaman çeşitli yardımcı metotlar kullanmaktaydık. Bunun nedeni Javascript'in dinamik bir dil olması ve herşeyin çalışma zamanında gerçekleşmesiydi. Bu nedenle bizler de yardımcı metotlara çalıştıracağımız metodun adını vererek çalışma zamanında bu metotları çağırabiliyorduk. Öncelikle gelin isterseniz geleneksel yöntemlerle çalışan bir Silverlight uygulaması geliştirelim ve daha sonra bu uygulamayı DLR'ı kullanacak şekilde değiştirelim.

Yazacağımız uygulama basit olarak Silverlight tarafından alacağı enlem ve boylam bilgileri ile Bing Maps'i kullanarak bize o enlem ve boylama sahip olan bölgeyi Bing Maps'i kullanarak gösterecek.

Uygulamamıza öncelikle Silverlight tarafındaki arayüzü tasarlayarak başlayalım ve enlem,boylam bilgilerini alacak şekilde arayüzümüzü tasarlayalım.

 

Arayüzü hazırladıktan sonra yapmamız gereken ise Silverlight tarafından çağıracağımız Javascript kodlarını yazmak. Bunun için öncelikle ilgili javascript kütüphanesini html dosyasından referans olarak alıyoruz.

<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"/>

Daha sonra ise haritayı bize gösterecek olan CreateMap isimli javascript metodumuzu yazıyoruz. Harita idsi map olan div elementinin içerisine yüklenecek. Bunun için Silverlight object taglerinin hemen altına bu div elementini ekliyoruz. Smile (Bing Maps ile ilgili daha detaylı bilgi edinmek isterseniz MSP arkadaşım Mehmet Aydın Bahadır'ın blogunu ziyaret edebilirsiniz.)

<script type="text/javascript">
  var map = null;
  function CreateMap(latitude,longtitude) { // Enlem ve boylam bilgileri alınır.
           var latlong = new VELatLong(latitude, longtitude);
           map = new VEMap("map"); // map id si olan div içerisinde harita yaratılır
           map.LoadMap(latlong, 5, 'h', false);  // Harita yüklenir        
  }
</script>

Javascript metodunu yazdıktan sonra gerçekleştireceğimiz son adım ise butona tıklandığı zaman Silverlight kodundan javascript metodunu çağırmak. Bunu gerçekleştirmek için System.Windows.Browser.HtmlPage nesnesinin Window isimli üyesi üzerinden Invoke metodunu çağıracağız. Invoke metodu içerisine öncelikle çağıracağımız javascript metodunun adını daha sonra javascript metoduna gönderilecek olan parametreleri vereceğiz. Tüm kod ise aşağıdaki gibi olacak.

HtmlWindow window = HtmlPage.Window;
private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
       window.Invoke("CreateMap", textBox1.Text, textBox2.Text);
}

Uygulamayı çalıştırdığımızda en başta ekranda tasarlarken verdiğimiz değerlere yakın bir değer verirsek Türkiye haritasını görebiliriz. Smile

Bu noktaya kadar uygulamayı şuana kadar kullandığımız yöntem olan yardımcı metot yöntemini kullanarak gerçekleştirdik. Şimdi ise gelelim Dynamic Language Runtime ile beraber kullanımına. Gereken değişiklikleri yapmadan önce Javascript Binder'ın çalışması için Microsoft.CSharp kütüphanesini projemize referans etmemiz gerekmekte. Normalde Microsoft.CSharp dll'ini Silverlight projesine referans olarak ekleyemiyoruz. Bunun için C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Libraries\Client klasöründe bulunan Microsoft.CSharp Silverlight dll'ini projemize referans olarak ekliyoruz. Artık yapmamız gereken sadece dinamik programlama.Wink

Öncelikle yukarıda statik bir şekilde olarak tanımladığımız HtmlWindow nesnesini bu sefer dinamik olarak tanımlayoruz. Daha sonra ise sanki C# tarafından bir kod çağırıyormuşuz gibi metot ismini kullanarak çağırımı gerçekleştireceğiz. Değişmiş kodumuz ise şu şekilde olacak.

dynamic window = HtmlPage.Window;
private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
       window.CreateMap(textBox1.Text, textBox2.Text);
}

Uygulamayı çalıştırdığımızda ise yine aynı şekilde Türkiye haritasını görüyoruz. Peki bu değişikliklerden sonra uygulamanın işleyişi nasıl değişti ? Öncelikle artık HtmlWindow nesnesi dinamik olarak tanımlandı. Yani artık nesnenin tipi ve sahip olduğu tüm metotlar çalışma zamanında belirlenecek ve çalışma zamanına kadar type-checking yapılmayacak. İşte bu nedenden dolayı artık window nesnesi üzerinden doğrudan yazdığımız javascript metodunu çağırabiliyoruz. Çünkü çağırım dinamik olarak yapılıyor.

Şimdi isterseniz işi biraz daha abartalım Laughing ve javascript tarafına yazdığımız metodu tamamen kesip C# tarafına yapıştıralım ve birde bu şekilde çağırım yapmaya çalışalım. Tabi öncelikle yazdığımız metodu javascript metodu yerine C# metodu haline getireceğiz. Bunun için öncelikle var olarak tanımladığımız değişkenleri bu sefer dynamic olarak tanımlayacağız ve böylece javascript tarafındaki işlevselliği C# tarafında da yakalayacağız. Son olarak ise new ile yarattığımız nesne aslında bir javascript nesnesi bu nedenle aynı syntaxı kullanarak C# tarafında javascript nesnesi yaratamıyoruz. Bunun için ise dinamik window nesnesini kullanıyoruz ve window.CreateInstance("Tip adı",Parametreler) şeklinde nesneyi yaratıyoruz. (Fark ettiğiniz gibi aslında burada bir dinamik çağrım yok. Bunun için yeni bir syntax üzerinde çalışılmakta. Final sürüm ile beraber Javascript nesneleri yaratmak için özel bir syntax eklenecek. Wink) Daha sonra ise bu sefer C# tarafında bulunan CreateMap metodunu çağırıyoruz.

dynamic window = HtmlPage.Window; private void btnUpdate_Click(object sender, RoutedEventArgs e) {    CreateMap(textBox1.Text, textBox2.Text); } dynamic map = null; void CreateMap(dynamic latitude, dynamic longtitude) { // Enlem ve boylam bilgileri alınır.    dynamic latlong = window.CreateInstance("VELatLong",latitude, longtitude);    map = window.CreateInstance("VEMap","map"); // map id si olan div içerisinde harita yaratılır    map.LoadMap(latlong, 5, 'h', false);  // Harita yüklenir         }

Gördüğünüz gibi tüm kodları artık C# ile yazdık ve tamamen dinamik bir şekilde kodlar işletildi. Son olarak C# tarafından Html içerisinde bulunan elementlere erişeceğiz. Hepimizin javascript tarafında kullandığı getElementById metodu artık C# tarafında da geçerli. Smile Bunun için HtmlDocument nesnesini dinamik olarak tanımlamamız yeterli. Mesela HTML sayfamıza idsi  message olan bir div elementi ekleyelim ve bu element içerisine harita yüklendikten sonra C# tarafından bir mesaj yazalım.

void CreateMap(dynamic latitude, dynamic longtitude)
{ // Enlem ve boylam bilgileri alınır.
   dynamic latlong = window.CreateInstance("VELatLong",latitude, longtitude);
   map = window.CreateInstance("VEMap","map"); // map id si olan div içerisinde harita yaratılır
   map.LoadMap(latlong, 5, 'h', false);  // Harita yüklenir
   dynamic document = HtmlPage.Document;
   dynamic messagedivision = document.getElementById("message");
   messagedivision.innerText = "A message comes from C#";
}

Bu makalemizde Dynamic Language Runtime içerisinde bulunan Javascript Binder mekanizmasını inceledik. Özellikle Javascript - Silverlight etkileşiminde Javascript Binder mekanizması yeni bir yaklaşım getirmekte. Ayrıca performans bakımından da herhangi bir handikap olmadan. Hatta caching mekanizması ile klasik yaklaşımdan daha da hızlı işletim elde edebilmekteyiz. Bununla ilgili sayısal bilgileri bir sonraki yazımda paylaşıyor olacağım.

Görüşmek Üzere



.NET Framework Beta 2 - Dynamic Language Runtime Performans İncelemesi

Merhaba Arkadaşlar, Bu yazımızda daha önce sürekli bahsettiğimiz ama bir türlü somut verilerle gözlemlemediğimiz Dynamic Language Runtime'ın performansına göz atıyor olacağız. Bildiğiniz gibi DLR içerisinde bulunan Call Site Caching mekanizması bizim yaptığımız dinamik çağrımları içerisinde cacheleyip ileriki çağrımlarda kodun daha hızlı işletilmesini sağlamakta. Biz de bu yazı boyunca DLR'ın içerdiği çeşitli mekanizmalar üzerinde yaptığımız dinamik çağrımları gözlemleyeceğiz ve Call Site Caching'in aslında ne kadar faydalı olduğunu somut veriler ile bir daha anlayacağız.

Object Binder

Object Binder mekanizmasını test ederken karşılaştırma yapacağımız yöntem reflection mekanizması olacak. Arka arkaya hem dinamik hem de reflection kodlarını işleteceğiz ve her bir kodun işletilmesi ne kadar sürüyor bunu gözlemleyeceğiz. Test için öncelikle basit bir Foo sınıfı tasarlayacağız ve içerisine bir property bir de bu propertyi ekrana yazan bir metot ekleyeceğiz. Daha sonra ise bu propertyi hem dinamik hem de reflection ile değiştirip sonra yine bu iki farklı mekanizma ile metot çağrımını gerçekleştireceğiz. Kodlar ise şu şekilde olacak. class Foo     {            public string MyProperty { get; set; }    public void Print()    {        HttpContext.Current.Response.Write("<br/>MyProperty = " + MyProperty);    } } Daha sonra ise Test metotlarını yazıyoruz.
protected void TestwithReflection()
{
   object obj = new Foo();
   Stopwatch watch = new Stopwatch();
   for (int i = 1; i < 11; i++)
   {
       watch.Restart();
       obj.GetType().GetProperty("MyProperty").SetValue(obj, string.Format("Test with Reflection -{0}", i), null);
       obj.GetType().GetMethod("Print").Invoke(obj, null);
       watch.Stop();
       Response.Write("&nbsp;&nbsp;&nbsp;Elapsed Time :<strong>" + watch.Elapsed.TotalMilliseconds + "</strong>");
   }
}
protected void TestwithDLR()
{
   dynamic obj = new Foo();
   Stopwatch watch = new Stopwatch();
   for (int i = 1; i < 11; i++)
   {
      watch.Restart();
      obj.MyProperty = string.Format("Test with DLR -{0}", i);
      obj.Print();
      watch.Stop();
      Response.Write("&nbsp;&nbsp;&nbsp;Elapsed Time :<strong>" + watch.Elapsed.TotalMilliseconds + "</strong>");
   }
}
Uygulamamızı çalıştırdığımızda ise aşağıdaki gibi bir sonuçla karşılaşıyoruz.
Gördüğümüz gibi DLR sadece ilk çağrımda çeşitli çözümlemeler yaptığından dolayı fazla zaman harcamaktadır. Ancak yapılan diğer çağrımlarda reflectiona oranla çok daha hızlı bir şekilde kodun işletilmesi söz konusu olmaktadır.

Javascript Binder

Test yapacağımız bir diğer platform ise Silverlight olacak. Bu sefer kodlarımızı hem javascript hem de dinamik olarak C# tarafında yazacağız ve işletim sürelerini inceleyeceğiz. Çalıştıracağımız kodda yine basit olarak result isimli div elementi içerisine 100 kere string değerler ekleyeceğiz. Kodlar ise şu şekilde olacak Javascript Kodları :  
function Test()
{
   for (var i = 0; i < 100; i++)
   {
       document.getElementById("result").innerHTML += "<br/>Call Test from javascript";
   }
}    
Daha sonra bu kodu C# tarafından hem dinamik olarak hem de window.Invoke yardımcı metoduyla çağırıyoruz.  Çıkan sonuçlar ise şu şekilde Herşey ortada Wink Not : Javascript tarafında hassas bir ölçüm yapamadığımdan dolayı aynı javascript kodunun dinamik olarak C# tarafında implemente edemedim. Javascript tarafında hassas ölçüm yöntemini araştırdıktan sonra RC sürümünde bu kullanımı da test edeceğim. Sonuçlara baktığımızda Call Site Caching yapısının DLR içerisinde ne kadar da önemli bir görev üstlendiğini görüyoruz. Böylece yaptığımız dinamik işlemler ilk çağrım haricinde yine hızlı bir şekilde yürütülmekte. Not : .NET Framework 4.0  şuanda Beta sürümünde olduğundan dolayı performanstan çok istenilen işlemlerin yapılmasına odaklanılmış durumda. Ancak Beta'dan sonra çıkacak olan sürümlerin performans açısından çok daha iyi olacaktır. Zaten .NET Framework 4.0 release tarihi de performans çalışmalarından dolayı 12 Nisan'a ertelenmiş durumda. RC sürümün çıkmasıyla yukarıdaki testleri yeniden yapacağım ve sonuçları sizinle paylaşacağım. Yaptığım örnekleri siz de buradan indirip test edebilirsiniz. Test Projects Herkese bol .NET'li günler...