İlkay İlknur
Just a developer...

Roslyn - Scripting API ve C# Interactive Window

Çarşamba, 1 Şubat 2012 10:51 by ilkayilknur

Merhaba Arkadaşlar,

Bir önceki yazımızda sizlerle Compiler As a Service konseptini inceleyerek Roslyn projesinin temelini oluşturan kavramları ve servisleri kısaca ve tamemen teorik olarak incelemiştik. Bu yazımızdan itibaren Roslyn ile derinlere dalmaya başlayacağız ve uygulamalı olarak Roslyn’i kullanmaya başlayacağız.

Önceki yazımızda Compiler içerisindeki servislerin birer API ile dışarıya açılmasının getireceği yeniliklerden bahsederken ilk sırada programlama dillerinin scripting özelliği kazanmasını söylemiştik. Scripting özelliği ile aslında uygulamalar içerisinde C# veya VB kodlarının dinamik olarak çalıştırılmasından söz etmekteyiz. Özellikle IronPython gibi dinamik programlama dillerine baktığımızda bu şekilde scripting özellikleri programlama dilinin yapısından dolayı mümkün olabilmekte. Hatta C# 4.0 ile beraber gelen dinamik programlama yenilikleri ve DLR (Dynamic Language Runtime) ile uygulamalarımız içerisinde şu anda Dinamik Programlama dillerinin kodlarını çalıştırabilmekteyiz.

Ancak konu C# ve VB kodlarının dinamik olarak çalıştırılabilmesine geldiğinde Roslyn öncesine kadar böyle bir şeyi gerçekleştirmek bizler için çok kolay değildi. Bunun için Reflection ve CodeDom tarafında bir takım derleme işlemleri yapmak gerekmekteydi.

Roslyn içerisinde bulunan Scripting API ile artık C# ve VB kodlarını uygulamalar içerisinde hızlı bir şekilde işletip sonuçlarını alabilmekteyiz. Şimdi ilk olarak bir Console uygulaması yaratalım ve bu uygulama içerisinden kodlarımızı dinamik olarak çalıştıralım.(Makale boyunca görmüş olduğunuz kodları çalıştırabilmek için  Roslyn.Compilers ve Roslyn.Compiler.CSharp dll’lerini referans olarak eklemeniz gerekmekte.)

ScriptEngine engine = new ScriptEngine();
engine.Execute(@"System.Console.WriteLine(""Hello Roslyn !!!"");");

 Yukarıdaki kodu doğrudan çalıştırdığımızda string olarak yazmış olduğumuz kodun C# compilerı tarafından işletildiğini ve Console uygulamamızın ekranına "Hello Roslyn !!!” yazdığını görüyoruz.

Şimdi biraz daha ileri gidelim ve değişken tanımlayıp bu tanımladığımız değişkeni bir alt satırda yazmış olduğumuz bir başka dinamik kod içerisinde kullanalım.

ScriptEngine engine = new ScriptEngine();
engine.Execute(@"int x = 5;");
engine.Execute(@"System.Console.WriteLine(x);");

 Yazmış olduğumuz kodu çalıştırdığımızda bakalım ne ile karşılaşacağız :)

Compiler tarafından ilk olarak yaptığımız tanımlama işletildikten sonra 2. sırada yazmış olduğumuz tanımladığımız değişkenin değerini Console’a yazdıran kod işletildiği sırada yukarıdaki exception fırlatılmakta ve x değişkeninin context içerisinde bulunmadığı söylenmekte. ;)

Buradan da çıkaracağımız sonuç şu olmalı ki ScriptEngine tipi içerisinde bulunan Execute metoduna sadece string olarak verdiğimiz C# veya VB kodları işletildikten sonra bu kodlar içerisinde yapılmış olan tüm tanımlamalar compiler tarafından unutulmakta. Peki bu tanımlamaların unutulmaması için ne yapmamız gerekiyor ?

Execution Context

C# veya VB kodlarının dinamik olarak işletilmesi sırasında daha önceden işletilen kodlarının compiler tarafından unutulmaması için kodların içerisinde çalıştırılacağı bir context belirlememiz gerekmekte. Bunun için de Roslyn tarafında kodumuzun içerisinde işletileceği bir Session belirlememiz gerekmekte ve Execute metoduna parametre olarak vereceğimiz kodun yaratmış olduğumuz Session içerisinde işletilmesi gerektiğini bildirmemiz gerekmekte.

ScriptEngine engine = new ScriptEngine();
Session session = Session.Create();
engine.Execute(@"int x = 5;", session);
engine.Execute(@"System.Console.WriteLine(x);", session);

 Şimdi biraz daha ileriye gidelim ve session içerisinde bir metot tanımlayalım ve daha sonra bu metodu çağıralım.

ScriptEngine engine = new ScriptEngine();
Session session = Session.Create();
engine.Execute(@"void Print (object x){ System.Console.WriteLine(x);}",session);
engine.Execute(@"int x = 5;", session);
engine.Execute(@"Print(x)", session);

 Şu ana kadar Roslyn tarafında dinamik kod işletme ile ilgili olarak temel kısımları inceledik. Ancak incelememiş olduğumuz bir nokta kaldı. O da dinamik olarak işletmiş olduğumuz kodun aslında çalıştırılmış olduğu host uygulama ile nasıl iletişimde olacağı.

Host Object

Host uygulama ile iletişimde bulunmak için Roslyn tarafında Host Object yapısını kullanmamız gerekmekte. Host Object dediğimiz yapı aslında herhangi bir tip olabilmekte. Bu tip, tanımlamış olduğumuz session içerisine dahil edilmekte ve böylece biz de dinamik olarak işleteceğimiz kodlar tarafında bu host object içerisinde bulunan tüm public üyelere erişebilmekteyiz ve istediğimiz işlemleri gerçekleştirebilmekteyiz. Örnek olarak host uygulama içerisnde şu şekilde içerisinde sayıları tutan ve bir takım işlemler gerçekleştiren bir sınıf tanımlayalım.

public class NumberList
{
      List<int> numbers = new List<int>();
      
      void Add(int i)
      {
           numbers.Add(i);
      }
      void PrintNumbers()
      {
           for (int i = 0; i < numbers.Count; i++)
           {
                 Console.WriteLine("{0}- {1}", i + 1, numbers[i]);
           }
       }
}

 

Yukarıda tanımlamış olduğumuz tip host uygulama olan Console uygulamamızda yer almakta. Şimdi sıra geldi bu tipi nasıl kullanacağımıza. Eğer bir tipi host object olarak kullanmak istiyorsak öncelikli olarak bu tipi ilgili Script Engine ve Session tiplerine bildirmemiz gerekmekte.

NumberList numberList = new NumberList();
ScriptEngine engine = new ScriptEngine(new[] 
                                  { typeof(NumberList).Assembly.Location });
Session session = Session.Create(numberList);
engine.Execute("Add(3);", session);
engine.Execute("Add(5)", session);
engine.Execute("PrintNumbers()", session);

 Uygulamamızı çalıştırdığımızda aşağıdaki gibi bir çıktı ile karşılaşmaktayız.

C# Interactive Window

C# ve VB programlama dillerine Scripting özelliğinin gelmesiyle beraber yapılabilecekler düşünüldüğünde aklımıza ilk olarak REPL(Read-Eval-Print-Loop) uygulamaları gelmekte. Yukarıda yapmış olduğumuz örneklere baktığımızda aslında bir REPL uygulaması yapmak için hemen hemen tüm parçalar elimizde. Bu nedenle REPL uygulaması kısmını tamamen size bırakıyorum ;) Ancak yine de takıldığınız noktalar olursa zaten internette Roslyn ile yapılmış pek çok REPL uygulaması bulunmakta bunlardan yararlanabilirsiz ya da İletişim bölümünden bana ulaşabilirsiniz.

Makalemizin sonlarına gelirken makalenin bu bölümünde aslında yine Roslyn ile beraber gelen ve Visual Studio içerisine entegre edilen bir REPL uygulamasından bahsediyor olacağım. Roslyn paketini bilgisayarınıza yükledikten sonra Visual Studio içerisinde View => Other Windows yolunu izlediğinizde burada “C# Interactive Window” seçeneğini görüyor olacaksınız. Buraya tıkladığımızda karşımıza gelen aslında C# kodları ile çalışan bir REPL uygulaması. Bu uygulama ile hızlı bir şekilde istediğimiz kodu yazıp sonucunu görebilmekteyiz.

Şimdi isterseniz buraya bir takım kodlar yazalım ve sonuçlarını inceleyelim.

Gördüğünüz gibi aslında bir C# uygulaması içerisinde yapabileceğimiz pek çok şeyi bu Window içerisinde yapabilmekteyiz ve sonuçlarını hemen görebilmekteyiz. Peki diğer dil özellikleri bu Window içerisinde destekleniyor mu diye soracak olursanız aslında compiler tarafından sağlanan bilgiler ile çalışan outlining, colorizer, intellisense gibi özellikler de bu window içerisinde çalışmakta. Burdan da anlıyoruz ki aslında compiler tarafından sağlanan farklı farklı API’lar birbirlerinden bağımsız olarak beraberce çalışabilmekteler. ;)

C# Interactive Window içerisinde bilmemiz gereken en önemli komutlardan biri de library referansı ekleme komutudur. #r “LibraryName” komutu ile Interactive Window içerisinde çalıştıracağınız kodlar ile ilgili gerekli referansları ekleyebilirsiniz.

Bunun yanında Interactive Window içerisindeki en güzel özelliklerden biri de yazmış olduğunuz uygulama içerisindeki kodları hızlı bir şekilde işletebilme ve sonuçlarını inceleyebilme şansı vermesi. Bunun için çalıştırmak istediğiniz kodu seçip Ctrl+Enter yapmanız yeterli. Yazmış olduğunuz kod Interactive Window içerisine kopyalanmakta ve işletilmekte. ;)

Eğer bir takım referanslar Interactive Window içerisinde tanımlı değilse kopyalamış olduğunuz kod Interactive Window içerisinde çalıştırılamayabilir. Bu nedenle öncelikle uygulama içerisinde referansların Interactive Window içerisinde referans olarak eklendiğinden emin olmamız gerekmekte. Bunun için de ilgili Project’e sağ tıklayarak “Reset Interactive Window From Project”’i seçmemiz gerekmekte.

Bu noktadan sonra ise artık yapmamız gereken ilgili kodu seçip Ctrl+Enter ile C# Interactive Window içerisinde işletmek.

Not : Interactive Window şu anda sadece C# için bulunmaktadır. İlerleyen sürümlerde VB için de Interactive Window duyurulacaktır.

Gördüğünüz gibi Compiler As a Service (CaaS) konsepti oldukça geniş ve bir o kadar da eğlenceli bir konu :) Bu yazımızda her ne kadar sadece Scripting API’yi incelemiş olsakta sırf bu API’yı kullarak bile yapabileceğimiz pek çok şey bulunmakta. Bu yüzden bir C# veya VB developer olarak herkese Roslyn projesini takip etmesini öneriyorum.

Umarım sizler için faydalı bir makale olmuştur.

Not: Makale içerisindeki kodlar Roslyn CTP-1 ile yazılmış ve test edilmiştir.

Tags:   , , ,
Categories:   C# | Roslyn
Actions:   E-mail | del.icio.us | Permalink | Yorumlar (0) | Yorumlar RSSRSS Yorum Takibi
Share

The Roslyn Project - 5N1K (Ne,nerede,ne zaman,nasıl,neden,kim)

Çarşamba, 25 Ocak 2012 13:34 by ilkayilknur

Merhaba Arkadaşlar,

C# 4.0 ve VB.NET 10 programlama dili sürümleriyle beraber Microsoft tarafında bu iki programlama dilini geliştiren ekipler tek bir çatı altında toplandı. Tek bir çatı altında toplanmasının temel nedeni de aslında programlama dillerini kullanan developerların benzer ihtiyaçlarının olması ve programlama dillerinin özelliklerinin birbirlerinden farklı olmasının önüne geçilerek  ortak temalar üzerinden ilerlenmesi idi.

Tüm bu çalışmalar kapsamında C# 4.0 sürümünün release olmasından sonra programlama dili ekipleri 2 ayrı takıma ayrılarak geliştirmelere devam etmekteler. Bir ekip şu anda C# 5.0 ve VB.NET 11 ( programlama dilleri arasındaki farklılıkları gidermek amacıyla VB 11 ile beraber C#’ta uzun zamandır bulunmakta olan Iterators özelliği geliyor olacak. ) dediğimiz programlama dillerinin bir sonraki versiyonu olan ve ana teması Asenkron Programlama olarak belirlenen geliştirmelere devam ederken bir diğer ekipte daha uzun soluklu bir proje olan Roslyn kod adlı projeye devam etmekteler.

Özellikler C# programlama dilinin geleceği ile ilgili araştırmalar yaptıysanız Compiler as a Service(CaaS) konseptiyle mutlaka karşılaşmışsınızdır. İşte Roslyn projesinin temel amacı da bu. Compiler as service, yani compiler’ın bir API vasıtasıyla servis olarak dışarıya açılması.

Şu anda C# ve VB compilerının yapısına  baktığımız zaman compilerların tam bir kara kutu olduğunu söyleyebiliriz. Çünkü compilerlar yazmış olduğumuz kaynak kodu input olarak alırlar , içeride sihir gerçekleşir ve output olarak .NET assemblyleri üretirler. Compiler aslında bu sihrin gerçekleşmesi sırasında yazmış olduğumuz kod ile ilgili pek çok analiz yapar ve bir takım yapılar oluşturur. Ancak .NET assemblysi üretilmesiyle beraber compiler yaratmış olduğu bu yapıları tamamen siler ve unutur.

Ayrıca syntax highlighting, go to definition, formatting veya refactoring gibi üretkenliğimizi arttıracak olan özelliklerde de baktığımız zaman IDE tarafından sağlanan bu özelliklere sıkı sıkıya bağlı olduğumuz görmekteyiz. Developer olarak kendi ihtiyaçlarımızı karşılayacak olan refactoring mekanizmalarını gerçekleştirmemiz oldukça zor. Aslında syntax highlighting, go to definition, formatting veya refactoring gibi özellikleri incelediğimizde tüm bu özellikler arka planda compiler’ın kodu derleme ve Assembly üretme sırasında kullanmış ve yaratmış olduğu yapıları kullanmakta.

Tüm okuduklarımızı düşündüğümüze Roslyn projesi ile amaçlanan compilerın kara kutu olmaktan çıkarılarak ve içerisinde bulunan bilgilerin bir API vasıtasıyla developerlara sunulmasıdır. Bu doğrultuda da C# ve VB compilerları kendi dillerinde !!! yani managed programlama dilleriyle yeniden implemente edilemekte. Evet yanlış okunmadınız :) Bir takım tarihsel nedenlerden dolayı C# ve VB compilerları C++ programlama dili ile yazılmıştır. Ancak Roslyn projesinden C# ve VB compilerları kendi dillerinde yeniden yazılmaktalar.

Compiler içerisindeki yapıları bir API ile dışarı sunulması peki developerlar için neler sağlayacak ? Aslında yapılabilecek pek çok şey bulunmakta. İlk aklımıza gelen, özellikle dinamik programlama dillerinde gördüğümüz Read-Eval-Print Loop’lar artık implemente edilebilir durumda olacak. Programlama dili içerisindeki scripting yeteneğinin bu şekilde hayata geçtiğini görüyor olacağız. Bunun yanında Meta-Programming dediğimiz aslında program yazan program olarak Türkçe’ye çevirebileceğimiz mekanizmalarda artık gerçekleştirilebiliyor olacak. Ayrıca Language-Object-Model’a sahip olarak, yazılan kod üzerinde tüm analizleri yapabiliyor olacağız. Kendi yazacağımız extensionlar veya uygulamalar ile çok çeşitli kendimize özel refactoring mekanizmalarını hayata geçirebiliyor olacağız. Ayrıca DSL(Domain – Spesific –Languages) Embeding dediğimiz kendi uygulamamıza has bir takım komutlar arasına C# veya VB kodu yerleştirebiliyor ve bu kodları da istediğimiz zaman işletebilir durumda oluyor olacağız.

Roslyn APIs

Yazmış olduğumuz kodların .NET assembly’si haline çevrilmesi süreci aslında compiler içerisinde 4 farklı süreci içerisinde barındırmakta.

Bunlar,

  • Parser : Kaynak kodu geçmiş olduğu ilk süreçtir. Bu süreç içerisinde kaynak kod parse edilerek kod tokenlara ayrılır. Ayrılan tokenlar aynı zamanda yapısal bir veri yapısına getirilirler. (Syntax Tree)
  • Symbols & Metadata Import : Bu aşamada kaynak kod içerisindeki tanımlamalar bulunur ve analiz edilir. Daha sonrasında ise sembol tabloları oluşturulması amacıyla bu tanımlamalar ile ilgili metadatalar okunarak sembol tabloları oluşturulur.
  • Binder : Bu aşamada da sembol tablosundaki tanımlamalarla kod içerisinde yapılmış olan tanımlamalar eşleştirilir.
  • IL Emitter : Son aşama olan bu aşamada ise tüm oluşturulan yapılar ve bilgiler birleştirilerek .NET Assembly’si oluşturulur.

Peki Compiler API’ları tam olarak bu süreçlerin neresine oturmakta ?

Compiler API’larını incelediğimizde aslında her bir süreci ayrı olarak içerisinde barındıran farklı API’ları görmekteyiz. Parsing süreci içerisinde Syntax Tree API bulunurken bu API ile Parsing işlemi sürecinde üretilen Syntax Tree üzerinde işlemler gerçekleştirilebilmekte. Aynı şekilde Symbol API, Binding and Flow APIs ve Emit API da geri kalan süreçler ile ilgili işlemleri içerlerinde barındırmakta.

Önceki paragraflarda IDE içerisinde bulunan ve developerların özellikle üretkenliklerini arttıran özelliklerin aslında compiler tarafından üretilen yapıları kullandığından bahsetmiştik. Peki hangi özellikler hangi aşamadaki bilgileri ve API’ları kullanmakta ?

Formatting, colorizer ve outlining gibi özelliklerin Parsing işlemi sonrasında üretilen Syntax Tree’yi kullandığını görmekteyiz. Navigate To ve Object Browser özellikleri de Symbol API tarafından sunulan Sembol Tablosuna dayanmakta. Intellisense, Rename, Extract Method, Go To Definition gibi IDE içerisinde bulunan pek çok özellikte Binding işlemi sonucunda üretilen yapılara dayanmakta. Edit and Continue ise Emit API tarafından gerçekleştirilmekte.

Compiler as Service konsepti aslında oldukça geniş ve içerisinde pek çok bilgiyi barındıran bir konsept. Roslyn projesinin tamamlanmasıyla beraber pek çok özelliğin geleceğini ve çok yaratıcı uygulamaların ortaya çıkacağını söylemek sanırım yanlış olmaz. Bu uzun soluklu projeyi en başından itibaren takip etmenizi şiddetle öneriyorum.

Roslyn projesinin ne zaman tamamlanacağını soracak olursanız açıkcası bunun için süre vermenin çok doğru olacağını düşünmüyorum. Ancak şunu söyleyebilirim ki C# 5.0 ile gelmiyor olacak :)

Roslyn projesinin şu anda CTP sürümü bulunmakta. Bu sürümü buradaki adresten indirip kurabileceğiniz gibi aynı zamanda NuGet Package Manager’a Roslyn yazarak ta projenize ekleyebilirsiniz ;) .

Bir sonraki yazımızda Roslyn ile derinlere dalıyoruz ;)

Tags:   ,
Categories:   C# | Roslyn
Actions:   E-mail | del.icio.us | Permalink | Yorumlar (0) | Yorumlar RSSRSS Yorum Takibi
Share