C#nedir?com
 
YAZAR HAKKINDA
Önsel Akın
Önsel Akın
http://nslkn.com
İletişme geçmek için tıklayın.
8 Makalesi yayınlanmakta.
Yazar hakkında detaylı bilgi için tıklayın.
Yayınlanan diğer makaleleri için tıklayın.
İlgili etiketler:  C# / VC#/.NET Önsel Akın
 
YAZI HAKKINDA
Türü : Makale
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
Seviyesi : Başlangıç
Kategori : C# / VC#/.NET
Yayınlanma Tarihi : 02.04.2004
Okunma Sayısı : 27220
Yorum Sayısı : 2     yorum yaz
Site İçi AramaSİTE İÇİ ARAMA
Üye Girişini AçÜye GİRİŞİ
Üye girişi için tıklayın.
Kullanıcı Adı
Şifre
 
Beni her zaman hatırla
Bir hafta boyunca kullanıcı bilgilerinizi kullanıcı çıkışı yapana kadar hatırlar. (Paylaşılan bilgisayarlarda önerilmez.)
 
Şifremi / Kullanıcı Adımı unuttum.
 
.net TV RSS Serbest KÖŞE (?)
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
uğur erdem
Alert - Jquery -ASP.NET
uğur erdem
yazının devamı >
oguzhan abalı
Silverlight'da Animation İşlemleri - Örnek Uygulama
oguzhan abalı
yazının devamı >
uğur erdem
Geliştirdiğimiz Windows Servisin Kurulumu Tamamlandıktan Sonra Çalışması
uğur erdem
yazının devamı >
Mehmet KAPLAN
WPF - Windows 7 Görev Çubuğu Programlama
Mehmet KAPLAN
yazının devamı >
Çağlar ÖZENÇ
SQL Server Express Utiliy SSEUTil.exe kullanın..
Çağlar ÖZENÇ
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Turhal Temizer 'in Blogu
Ülkelerine Göre Araç Markaları 26.07.2014
Turhal Temizer 'in Blogu
Araç Segmenleri 26.07.2014
Burak Selim Senyurt
Yazılımcı Empatisi 23.07.2014
Burak Selim Senyurt
NLog için Oracle Database Kullanmak 18.07.2014
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Uzman Abi
Her Yönüyle C# - Sefer Algan
C# Kod Derleyicisi
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon
Genel olarak tasarlanmış bir yazılımın, farklı kullanıcıların tüm ihtiyaçlarını karşılaması çok zordur. Daha geniş bir kullanıcı grubuna hitab eden yazılım geliştirmek için izlenebilecek ilk yol tasarım sırasında olabildiğince farklı durumu incelemek ve tasarımı bu durumlara göre yapmak, diğer bir yol ise yazılıma esneklik katmaktır. Esnek bir yazılım, üretim ortamına taşındıktan sonra da kullanıcılar tarafından geliştirilmeye açık olan yazılımdır. Bir anlamda, programcıların bıraktıkları noktadan, yazılımı geliştirme işini kullanıcılar devralmalıdır.  Kullanıcılara bu imkanı sağlamak için ise, tasarım araçları (form, iş akışı) ve programlama araçlarından (api’ler, scripting dilleri, script motorları)  faydalanılır.

Bu yazıda C# ile programlarımıza nasıl esneklik katabileceğimizi, programımızı nasıl bir kod derleyiciye dönüştürebileceğimizi göreceğiz.

CSharpCodeProvider Sınıfı

Programımıza bir kod derleyicinin sahip olduğu yetenekleri vermek aslında düşünüldüğü kadar zor değil. Framework zaten bu görevi yerine getiren bir sınıf barındırıyor. Bizim yapacağımız şey ise bu sınıfı kullanmak ve birkaç ekstra özellik ekleyerek tek bir metod çağrısı ile istenen kodun derlenip çalıştırılmasını sağlamak. Sözünü ettiğimiz sınıf olan CSharpCodeProvider sınıfı, C# kodlarını derleyen ve CodeDOM kod modellerini kaynak koduna dönüştüren nesnelere ulaşmamızı sağlar.

Yukarıda saydığımız büyük işleri küçük bir metodla gerçekleştiren sınıfımızı yazmaya başlayalım. Sınıfımıza CodeRunner adını verdim.

Öncelikle bize gerekli olan isim uzaylarını belirtiyoruz.

using System;

using System.IO;

using System.Text;

using System.Reflection;

using Microsoft.CSharp;

using System.CodeDom.Compiler;

using System.Collections.Specialized;

Bir sonraki adım sınıf tanımını oluşturmak;

namespace CodeRunnerLib

{

       public class CodeRunner

        {

             public static StringCollection ReferencedAssemblies = new StringCollection();

             public static StringCollection NameSpaces = new StringCollection();

             static CodeRunner()

             {

                    ReferencedAssemblies.Add("System.dll");

                    NameSpaces.Add("System");

             }

Yukarıdaki kod parçası içerisinde iki adet değişken tanımladık. ReferencedAssemblies adındaki StringCollection nesnesi, derlenecek olan kod için gerekli harici assembly’leri referanslara eklemek için kullandığımız değişken.

NameSpaces adındaki diğer StringCollection nesnesi ise derlenecek olan kodun başına “using ...” ifadesi ile eklenecek isim uzaylarının listesini saklayan değişken.

CodeRunner sınıfının yapılandırıcısını (constructor) statik olarak tanımladım çünkü CodeRunner sınıfı tek bir statik metoda sahip. Böylece CodeRunner sınıfını kullanabilmek için bir CodeRunner nesnesi oluşturmamıza da gerek kalmıyor. Statik yapılandırıcı içerisinde “System.dll” dosyasını referanslara ekliyoruz. Ayrıca “using” ifadesi ile derlenecek kodun başında yer alması için NameSpaces koleksiyonuna “System” isim uzayını ekliyoruz.

public static CompilerErrorCollection RunCode(string Code) {
CodeRunner sınıfının tek metodu olan RunCode metodunun tanımını yukarıda görüyorsunuz. Metod, parametre olarak bir string alıyor ve derleme işleminin sonuçlarını içerisinde bulunduran bir CompilerErrorCollection nesnesi döndürüyor.

CSharpCodeProvider cp = new CSharpCodeProvider();
Kodları derleme ve hataları döndürme işlemlerinde kullanacağımız ICodeCompiler arayüzüne ulaşmamızı sağlayan CSharpCodeProvider nesnesini tanımladık. Şimdi bahsettiğimiz işlemleri yapabilmek için CodeProvider nesnesinin bir kod derleyici üretmesini ve bize döndürmesini sağlayalım;

ICodeCompiler derleyici = cp.CreateCompiler();
CSharpCodeProvider sınıfının CreateCompiler metodunu kullanarak ICodeCompiler arayüzünü uygulayan bir derleyici sınıf elde ettik. RunCode metoduna parametre olarak geçilen kodları derlemek için artık bu arayüzü kullanabiliriz.

CompilerParameters derleyiciParams = new CompilerParameters();
Derleme işleminin konfigurasyonunu yapabilmek için bir CompilerParameters nesnesi tanımladık. Bu nesnenin birkaç özelliğini değiştirip derleyici nesnesine, kodları nasıl derleyeceğini bildireceğiz.

foreach (string refAs in ReferencedAssemblies)

{

    derleyiciParams.ReferencedAssemblies.Add(refAs);

}

Daha önce CodeRunner sınıfına eklediğimiz ReferencedAssemblies koleksiyonu içerisinde bulunan tüm assembly isimlerini derleyiciParams adındaki CompilerParameters nesnesi aktardık. Böylece derleyici arayüzü, kodları derlerken hangi assembly’leri kullanması gerektiğini bilecek.

derleyiciParams.GenerateInMemory = true;
Yukarıdaki ifade ile derleme işlemi bittikten sonra, çıktının (assembly) hafızada tutulacağını belirtmiş oluyoruz. Eğer derleme işlemi sonucunda elde edilen assembly’nin hafızada değil de diskte saklanmasını istiyorsanız CompilerParameters sınıfının GenerateInMemory özelliğini false yapıp, OutputAssembly özelliğinde bir dosya adı belirtmelisiniz.

StringBuilder sbKod = new StringBuilder();

IndentedTextWriter kodYazici = new IndentedTextWriter(new StringWriter(sbKod));

foreach (string nSpace in NameSpaces)

{

    kodYazici.WriteLine("using {0};", nSpace);

}

kodYazici.WriteLine("public class DinamikSinif {");

kodYazici.Indent += 3;

kodYazici.WriteLine("public void DinamikMetod() {");

kodYazici.Indent += 3;                   

kodYazici.Write(Code);

kodYazici.Indent -= 3;

kodYazici.WriteLine("}");

kodYazici.Indent -= 3;

kodYazici.WriteLine("}");

kodYazici.Close();

Yukarıdaki satırlarda tam bir kod dosyası hazırlayıp bir StringBuilder nesnesi içerisinde saklıyoruz. Kodları yazdırmak için kullandığım nesne bir IndentedTextWriter nesnesi. Bu nesneyi CodeDOM ile kod oluştururken ya da bizim yaptığımız gibi dinamik kod geliştirirken kullanabilirsiniz. IndentedTextWriter nesnesinin ilginç olan tek özelliği Indent adındaki özellik. Bu özellik WriteLine ya da Write ile yazdığımız kod satırlarının Indent kadar girintili olarak yazılmasını sağlıyor.

Yukarıdaki kodda önemli olan tek nokta şu:

CodeRunner.RunCode metoduna parametre olarak geçilen tüm kodları tam bir sınıf tanımı içerisinde saklıyoruz. Önce NameSpaces koleksiyonuna eklenen tüm isim uzaylarını using ifadesi ile üretilen kodun başına ekliyoruz. Daha sonra dinamik bir sınıf tanımlıyor, sınıf içerisinde geçici bir metod oluşturuyor ve parametreden gelen kodları bu dinamik metod içerisine yerleştiriyoruz.

Örneklemek gerekirse;

RunCode metoduna parametre olarak “MessageBox.Show(“Test”);”  geçilmiş olsun. Bu durumda oluşturulan dinamik sınıf tanımı şu şekilde:

using System;

public class DinamikSinif

{

     public void DinamikMetod()

     {

         MessageBox.Show("Test");

     }

}

Tabi yukarıdaki kodun çalışabilmesi için CodeRunner.References koleksiyonuna “System.Windows.Forms.dll” ve NameSpaces koleksiyonuna “System.Windows.Forms” eklenmeli...

CompilerResults derlemeSonuclari = derleyici.CompileAssemblyFromSource(derleyiciParams, sbKod.ToString());
Bir sonraki adımda derleyici nesnesini kullanarak oluşturduğumuz dinamik sınıf kodunu, belirlediğimiz ayarlarla (derleyiciParams) derliyoruz. Derleme işleminin sonucu derlemeSonuclari adında bir CompilerResults nesnesi içerisinde saklanıyor. Eğer derleme sırasında bir hata varsa, hata ile ilgili bilgiler –hata olan satırın numarası ve hata mesajı- bu nesnenin Errors koleksiyonunda barındırılıyor. Ayrıca derleme işlemi başarılı ise, derlenen assembly’ye CompilerResults.CompiledAssembly özelliğinden ulaşıyoruz.

if (derlemeSonuclari.Errors.HasErrors)

{

    return derlemeSonuclari.Errors;

}

Eğer derleme işlemi sırasında bir hata ile karşılaşılırsa hatalar RunCode metodunun dönüş değeri olarak belirleyip metoddan çıkıyoruz. Böylece RunCode metodunu çağıran tüketiciler işler yolunda gitmezse hatalarla ilgili bilgilere ulaşabiliyorlar.

Assembly derlenmis = derlemeSonuclari.CompiledAssembly;
Eğer hatasız bir derleme işlemi gerçekleşmişse derlenen assembly’yi derlenmis adındaki değişkende saklıyoruz. Şimdi biraz Reflection kullanarak dinamik olarak derlediğimiz assembly içerisindeki dinamik sınıfımızın bir örneğini oluşturabiliriz;

object dinamikSinif = derlenmis.CreateInstance("DinamikSinif");
derlenmis ile sakladığımız assembly içerisindeki DinamikSinif nesnesinin bir örneğini assembly’nin CreateInstance metodunu kullanarak oluşturduk. Bir sonraki adım yine dinamik olarak oluşturduğumuz metodu çağırmak;

Type dinamikSinifTipi = dinamikSinif.GetType();

dinamikSinifTipi.InvokeMember("DinamikMetod", BindingFlags.InvokeMethod, null, dinamikSinif, null);

return null;

Metodu çağırabilmek için önce Reflection kullanarak dinamikSinif nesnesinin tip tanımına ulaşıyoruz. Daha sonra tip tanımı üzerinden InvokeMember metodu ile DinamikMetod adındaki metodu çağırıyoruz. Böylece RunCode metoduna parametre olarak geçilen C# kodu sanal bir sınıf içerisindeki sanal bir metod içine gömülerek çalıştırılmış oluyor.

Aşağıda CodeRunner sınıfının tam kodunu bulabilirsiniz. Ayrıca yazının sonunda CodeRunner sınıfı ve test için kullanabileceğiniz bir winforms uygulamasının kaynak kodları da mevcut...

Önsel Akın

MCSD.Net, MCSE, MCDBA, CCNA

onsel.akin@bilgeadam.com

using System;

using System.IO;

using System.Text;

using System.Reflection;

using Microsoft.CSharp;

using System.CodeDom.Compiler;

using System.Collections.Specialized;

namespace CodeRunnerLib {

       public class CodeRunner {

             public static StringCollection ReferencedAssemblies = new StringCollection();

             public static StringCollection NameSpaces = new StringCollection();

             static CodeRunner() {

                    // Statik yapılandırıcı fonksiyon içerisinde

                    // System isim uzayına referans gösteriyoruz

                    ReferencedAssemblies.Add("System.dll");

                    NameSpaces.Add("System");

             }

             public static CompilerErrorCollection RunCode(string Code) {

                    /* Metin kutusuna yazılan kodu derlemek için

                     * bir CSharpCodeProvider nesnesi oluşturuyoruz.

                    */

                    CSharpCodeProvider cp = new CSharpCodeProvider();

                    ICodeCompiler derleyici = cp.CreateCompiler();

                    /* Kod derleyiciyinin birkaç özelliğini ayarlayabilmek

                     * için bir CompilerParameters nesnesi oluşturuyoruz.

                     */

                    CompilerParameters derleyiciParams = new CompilerParameters();

                    // Derleyiciye gerekli olan assembly’leri referansla gösteriyoruz

                    foreach (string refAs in ReferencedAssemblies) {

                           derleyiciParams.ReferencedAssemblies.Add(refAs);

                    }

                    // Derlenen assembly’nin hafızada tutulmasını istiyoruz

                    derleyiciParams.GenerateInMemory = true;

                    /* Derlenecek olan kodu oluşturuyoruz.

                     * Metin kutusuna yazılan kodu, dinamik olarak oluşturduğumuz

                     * bir sınıf içerisine gömeceğiz

                     */

                    StringBuilder sbKod = new StringBuilder();

                    IndentedTextWriter kodYazici = new IndentedTextWriter(new StringWriter(sbKod));                   

                    // Derlenecek kod için gerekli olan isimuzaylarını aktarıyoruz

                    foreach (string nSpace in NameSpaces) {

                           kodYazici.WriteLine("using {0};", nSpace);

                    }

                    // Sınıf tanımını oluşturalım

                    kodYazici.WriteLine("public class DinamikSinif {");

                    kodYazici.Indent += 3;

                    kodYazici.WriteLine("public void DinamikMetod() {");

                    kodYazici.Indent += 3;                   

                    // Parametrede gelen kodu, geçici sınıf metodu içerisine yerleştiriyoruz

                    kodYazici.Write(Code);

                    kodYazici.Indent -= 3;

                    kodYazici.WriteLine("}");

                    kodYazici.Indent -= 3;

                    kodYazici.WriteLine("}");

                    kodYazici.Close();

                    // Kodu derliyoruz, derleme işleminin sonuçlarını saklamak için bir CompilerResult nesnesi oluşturuyoruz

                    CompilerResults derlemeSonuclari = derleyici.CompileAssemblyFromSource(derleyiciParams, sbKod.ToString());

                    // Derleme işlemi sonucunda bir problem varsa bunları gösteriyoruz

                    if (derlemeSonuclari.Errors.HasErrors) {

                           return derlemeSonuclari.Errors;

                    }

                    // Derlenmiş olan assembly’yi alıyoruz

                    Assembly derlenmis = derlemeSonuclari.CompiledAssembly;

                    // Assembly içerisinden kendi eklediğimiz sınıfın bir örneğini oluşturuyoruz

                    object dinamikSinif = derlenmis.CreateInstance("DinamikSinif");

                    // DinamikSinif’a ait DinamikMetod adındaki metodunu çağırıyoruz

                    Type dinamikSinifTipi = dinamikSinif.GetType();

                    dinamikSinifTipi.InvokeMember("DinamikMetod", BindingFlags.InvokeMethod, null, dinamikSinif, null);

                    return null;

             }

       }

}

CodeRunner ve Test Uygulaması Kaynak Kodları

Makale:
C# Kod Derleyicisi C#, Visual C# ve .NET Önsel Akın
  • Yazılan Yorumlar
  • Yorum Yaz
EKİ
29
2006
tşkler.dll dosyasını J# ta kullanabilir miyiz?
Sayfalar : 1 
Yorum yazabilmek için üye girişi yapmalısınız. Üye girişi için tıklayın.
Üye değilseniz Üyel Ol linkine tıklayarak üyeliğinizi hemen başlatabilirisniz.
 
  • Bu Konuda Son 10
  • Eklenen Son 10
  • Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor