SİTE
İÇİ ARAMA |
|
Blogroll |
|
|
|
CodeDom, AppDomain ve Plug-in Tabanlı Programlama |
|
Gönderiliyor lütfen bekleyin... |
|
|
Bu makalemde CodeDom sınıfını kullanarak çalışma
zamanında kod derleme, AppDomain sınıfı ve Application Domain yönetimine ve
son olarakda plug-in tabanlı programlama konularına değineceğim. Yaygın olarak
kullanılan uygulamalardaki genel sorun yazılımın özelleştirme olanaklarının,
esnekliğinin, uyarlanabilirliğinin yetersiz olmasıdır.Bu özellikler ve nitelikler
sektöre hitab eden yazılımların ön plana çıkmalarındaki en önemli kriterlerdir.
Hepimiz geliştirdiğimiz uygulamaların uyarlama bölümünde bu tür sıkıntıları
yaşamışızdır.Bazen konu o kadar geniştir ki, yazılımın belirli bölümlerinde
kontrolün kullanıcıda olması gerekir veya sizin kullanıcının taleplerine çok
kısa sürede cevap vermeniz gerekebilir.Bu tür durumlarda plug-in tabanlı uygulamalar
geliştirmemiz gerekir. Plug in tabanlı programlama konusuna girmeden önce uzun
süredir ilgimi çeken diğer bir konuya değinmek istiyorum.
Çalışma zamanında .net kodu oluşturmak/derlemek.
.Net ile uyumlu dilleri kullanarak çalışma zamanında
kod oluşturma veya derleme yapma imkanımız mevcuttur. İlk bakışta aklınıza -"bu
tür bir özelliği nerde kullanabiliriz?" sorusu gelebilir.Birkaç örnek vermek
gerekirse kendi IDE nizi geliştirebilir veya
çalışma zamanında yazdığınız kodu derleyip, yazılımda herhangi bir güncelleme
yapmadan uygulamanızın içinde kullanabilirsiniz. .Net ile çalışma zamanında
kod oluşturmak için System.CodeDom sınıfını ve derlemek için kullandığımız dile
ait referans sınıfını kullanırız (c# için Microsoft.CSharp).
System.CodeDom İsim Alanı(Namespace)
Bu isim alanı bize .Net dili oluşturmak için
gerekli sınıfları sunar. .Net dilinin yapısı tam olarak bu sınıf altında özetlenmiştir
diyebiliriz. Birkaç örnek vermemiz gerekirse;
Sınıf ismi |
Açıklama |
System.CodeDom.CodeNamespace
|
namespace tanımlamamızı sağlar.
|
System.CodeDom.CodeComment
|
kod yorumu tanımlamamızı sağlar.
|
System.CodeDom.CodeTypeDecleration
|
sınıf, yapı, arayüz gibi nesnelere
tür atamamızı sağlar. |
System.CodeDom.CodeEntryPointMethod
|
bir assembly nin giriş metodunu
belitmemizi sağlar. |
System.CodeDom.CodeTypeReferenceExpression |
referans tür belirtmemizi sağlar. |
System.CodeDom.CodeMethodInvokeExpression |
metod çalıştırmamızı sağlar. |
System.CodeDom.CodeCompileUnit |
CodeDom sınıflarını içerir. |
CodeCompileUnit sınıfı
.Net dillerinde kodun belli bir etki alanı mevcuttur.Yazdığımız
kod bir üye ye aittir bu üye bir sınıfa, seçimli olarak sınıf da bir isimalanına.
Kod yazarken ilk olarak isimalanı sonra sınıf ardından üyeleri oluşturur ve
gerekli kodları üyelere yazarız. Özetlemek gerekirse CodeDom isimalanındaki
sınıfları kullanarak kod oluştururken aynı yöntemi uygulayacağız. CodeDom isimalanındaki
bütün sınıflar bir ağaç yapısındadır ve en tepedeki sınıf CodeCompileUnit sınıfıdır.Kısaca
bu sınıf .Net kod parçalarını içerir.
Bu yapı kod grafiği olarak isimlendirilmektedir.
.Net kodunun çalışma zamanında oluşturulması
Kod oluşturmak veya derlemek için üreteceğimiz
veya derleme yapacağımız kodun dilini destekleyen sınıfları kullanırız. C# dili
için bu Microsoft.CSharp isimalanı altındaki CSharpCodeProvider sınıfı, VB dili
için Microsoft.VisualBasic isimalanı altındaki VBCodeProvider sınıfıdır. Bu
sınıfların CompileAssemblyFromDom, CompileAssemblyFromFile veya CompileAssemblyFromSource
metodlarını kullanırız.
Metod ismi |
Açıklama |
CompileAssemblyFromDom
|
Kod grafiği yani CodeDom nesneleriyle
derleme yapılır |
CompileAssemblyFromFile |
Kod bir dosyadan okunarak derleme
yapılır |
CompileAssemblyFromSource |
Metoda kod parametre olarak
gönderilerek derleme yapılır. |
HelloWorld örneği
CodeDom isimalanındaki sınıfları kullanarak
HelloWorld kodu üretecek bir örnek yapalım.
HelloWorld.cs
|
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using Microsoft.CSharp;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// CompileUnit nesnesi yaratılıyor.
CodeCompileUnit compileUnit = new CodeCompileUnit();
// Acme ismiyle bir CodeNameSpace nesnesi yaratılıyor.
CodeNamespace samples = new CodeNamespace("Acme");
// compileUnit nesnesine ekleniyor.
compileUnit.Namespaces.Add(samples);
// System isimalanı ekleniyor.
samples.Imports.Add(new CodeNamespaceImport("System"));
// Class1 ismiyle CodeTypeDecleration nesnesi yaratılıyor
CodeTypeDeclaration class1 = new CodeTypeDeclaration("Class1");
// compileUnit nesnesine ekleniyor.
samples.Types.Add(class1);
// programın giriş noktasını belirlemek için CodeEntryPointMethod nesnesi yaratılıyor
CodeEntryPointMethod start = new CodeEntryPointMethod();
// System.Console sınıfı için tanımlamalar yapılıyor.
CodeTypeReferenceExpression csSystemConsoleType = new CodeTypeReferenceExpression("System.Console");
// Console.WriteLine satırı yaratılıyor.
CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
csSystemConsoleType, "WriteLine",
new CodePrimitiveExpression("Hello World!"));
// WriteLine satırı programın giriş noktası olan metoda ekleniyor.
start.Statements.Add(cs1);
// İkinci WriteLine satırı ekleniyor.
CodeMethodInvokeExpression cs2 = new CodeMethodInvokeExpression(
csSystemConsoleType, "WriteLine",
new CodePrimitiveExpression("Press the Enter key to continue."));
// WriteLine satırı programın giriş noktası olan metoda ekleniyor.
start.Statements.Add(cs2);
// System.Console.ReadLine komutu yaratılıyor.
CodeMethodInvokeExpression csReadLine = new CodeMethodInvokeExpression(
csSystemConsoleType, "ReadLine");
// ReadLine satırı programın giriş noktası olan metoda ekleniyor.
start.Statements.Add(csReadLine);
// Programın giriş noktası olan metod sınıf üyelerine ekleniyor.
class1.Members.Add(start);
// Kodun oluşturulması için gerekli nesneler yaratılıyor.
Stream str = File.Open("c:\\kod.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(str);
// C# kodumuzu oluşturacak CSharpCodeProvider ve ICodeGenerator nesneleri yaratılıyor.
CSharpCodeProvider csProvider = new CSharpCodeProvider();
ICodeGenerator cg = csProvider.CreateGenerator(sw);
// compileUnit nesnesi içinde bulunan kod dosyaya aktarılıyor.
cg.GenerateCodeFromCompileUnit(compileUnit, sw, new CodeGeneratorOptions());
// İşi biten nesneler kapatılıyor.
sw.Close();
str.Close();
}
}
}
|
Örneğimizi çalıştırdığımızda bize C:\kod.txt
dosyasını oluşturacaktır.
kod.txt
|
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:2.0.50727.42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
namespace Acme {
using System;
public class Class1 {
public static void Main() {
System.Console.WriteLine("Hello World!");
System.Console.WriteLine("Press the Enter key to continue.");
System.Console.ReadLine();
}
}
}
|
Dikkat ederseniz CodeDom sınıfını açıklarken
c# diline bağımlı kalmadan, .Net dillerinin oluşturulup derlenebileceğinden
bahsettim.HelloWorld.cs örneğindeki kod ile CodeDom yapısını destekleyen bütün
dillerde kod oluşturabilir, derleyebiliriz. İsterseniz aynı örneği sadece iki
satırını değiştirerek vb.net kodu üretmesi için uyarlayalım.
HelloWorld.cs
|
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using Microsoft.VisualBasic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
......
......
......
// Vb kodumuzu oluşturacak VBCodeProvider ve ICodeGenerator nesneleri yaratılıyor.
VBCodeProvider csProvider = new VBCodeProvider();
ICodeGenerator cg = csProvider.CreateGenerator(sw);
// compileUnit nesnesi içinde bulunan kod dosyaya aktarılıyor.
cg.GenerateCodeFromCompileUnit(compileUnit, sw, new CodeGeneratorOptions());
// İşi biten nesneler kapatılıyor.
sw.Close();
str.Close();
}
}
}
|
Örneğimizi çalıştırdığımızda bize C:\kod.txt
dosyasını vb.net dilinde oluşturacaktır.
kod.txt
|
------------------------------------------------------------------------------
<auto-generated>
This code was generated by a tool.
Runtime Version:2.0.50727.42
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
</auto-generated>
------------------------------------------------------------------------------
Option Strict Off
Option Explicit On
Imports System
Namespace Acme
Public Class Class1
Public Shared Sub Main()
System.Console.WriteLine("Hello World!")
System.Console.WriteLine("Press the Enter key to continue.")
System.Console.ReadLine
End Sub
End Class
End Namespace
|
CodeDom isimalanı gördüğünüz gibi dilden bağımsız
kodun temsil edilmesini sağlar.
.Net kodunun çalışma zamanında derlenmesi
.Net kodu derleme için derleyeceğimiz dilin ilgili
sınıflarını kullanacağız.Kod oluşturma işleminden farklı olarak derleme parametrelerini
belirlemek için CompilerParameters sınıfı kullanmamız gerekmektedir.Sonuç olarak
bu işlemi csc.exe yi çalıştırmakla aynı sayabilirsiniz.csc.exe derleme programının
aldığı parametreleri burda CompilerParameters sınıfı ile temsil ediyoruz.C#
kodu derlemek için CSharpCodeProvider sınıfını kullanacağız.
HelloWorld.cs
|
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using Microsoft.CSharp;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
......
......
......
// C# kodumuzu oluşturacak CSharpCodeProvider ve ICodeGenerator nesneleri yaratılıyor.
CSharpCodeProvider csProvider = new CSharpCodeProvider();
ICodeGenerator cg = csProvider.CreateGenerator(sw);
// compileUnit nesnesi içinde bulunan kod dosyaya aktarılıyor.
cg.GenerateCodeFromCompileUnit(compileUnit, sw, new CodeGeneratorOptions());
// İşi biten nesneler kapatılıyor.
sw.Close();
str.Close();
CSharpCodeProvider provider = new CSharpCodeProvider();
// derleme parametreleri için CompilerParameters türünden bir nesne oluşturuyoruz.
CompilerParameters cp = new CompilerParameters();
// Projenin System.dll i referans gösterdiğini belirtiyoruz.(opsiyonel)
cp.ReferencedAssemblies.Add("System.dll");
// çalıştırılabilir bir assembly dosyası derlenmesi için özellik atanıyor.
cp.GenerateExecutable = true;
// derlenecek assembly dosyasını belirtiyoruz.
cp.OutputAssembly = "c:\\HelloWorld.exe";
// kodun belleğe derlenmemesi için bu özelliğe false değerini atıyoruz.
cp.GenerateInMemory = false;
// kod derleniyor.
CompilerResults cr = provider.CompileAssemblyFromFile(cp, new string[] {"C:\\kod.txt" });
// eğer hatalar mevcutsa ekrana basılıyor.
if (cr.Errors.Count > 0)
{
Console.WriteLine("Derlemede Hata(lar) oluştu...");
foreach (CompilerError ce in cr.Errors)
{
Console.WriteLine(ce.ToString());
}
}
}
}
}
|
C:\HelloWorld.exe miz derlenmiş durumdadır.
|
AppDomain sınıfı ve yönetimi
İşletim sistemleri genel olarak çalıştırdıkları uygulamalarda oluşacak herhangi bir problemin diğer çalışan uygulamaları etkilemesini önlemek için bu uygulamalar arasında bir izolasyon uygularlar.
Bellek adresleri uygulamaya bağımlıdırlar.A uygulamasından B uygulamasına gönderilen bellek adresinin B uygulaması tarafından kullanılması, B uygulamasını %100 güvenli kılmaz.Bunun sebebi gönderilen bellek adresinin A uygulaması tarafından B’den habersiz olarak değiştirilebiliyor olmasıdır.
AppDomain sınıfı uygulamamızın çalıştığı domainin özelliklerine erişmemizi,
yeni application domain yaratmamızı veya yarattığımız domainlerin
bellekten kaldırılmasını sağlar.AppDomain sınıfına bu makalede değinmemin
sebebi plug in konusuna bir ön hazırlık yapmaktır.Plug in konusunda
uygulamamıza dinamik olarak dll assemblyleri yükleyip çalıştıracağız.Normalde
çalışma zamanında AppDomain sınıfının Load veya Assembly sınıfının
LoadFile metodyla dll dosyaları yüklememiz mümkündür.Fakat yüklenen
assembly uygulamamızın çalıştığı application domaine yüklenecektir.Yüklediğimiz
assembly dosyalarını bellekten kaldırma olanağımız mevcut değildir.Bunu
ancak application domaini bellekten kaldırarak yapabiliriz ki bu mevcut çalışan
uygulamamızın da sonlanması demektir.
Bu sorunu aşmak için çalışma zamanında yükleyeceğimiz assembly dosyalarının
yeni bir AppDomain de yüklenmesini sağlamamız gerekmektedir.AppDomain sınıfı
bize yeni domainler yaratmamıza imkan sağlamaktadır.
Yeni bir AppDomain yaratmak
Yeni bir AppDomain yaratmak için AppDomain sınfıının CreateDomain metodunu
çağırmamız gerekmektedir.
YeniAppDomain.cs
|
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
AppDomain domain = AppDomain.CreateDomain("Yiğit");
Console.WriteLine("Yeni yaratılan domain ismi: {0}",domain.FriendlyName);
Console.WriteLine("Mevcut domain ismi: {0}", AppDomain.CurrentDomain.FriendlyName);
}
}
}
|
Uygulamamızı çalıştırdığımızda
iki ayrı application domaine sahip olacağız.
Mevcut bir AppDomainin bellekten kaldırılması
için AppDomain sınıfına ait Unload metodunu çağırmamız yeterli olacaktır.
YeniAppDomain.cs
|
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
AppDomain domain = AppDomain.CreateDomain("Yiğit");
Console.WriteLine("Yeni yaratılan domain ismi: {0}",domain.FriendlyName);
Console.WriteLine("Mevcut domain ismi: {0}", AppDomain.CurrentDomain.FriendlyName);
AppDomain.Unload(domain);
try
{
Console.WriteLine("Yeni yaratılan domain ismi: {0}", domain.FriendlyName);
}
catch (Exception excp)
{
Console.WriteLine("{0}", excp.Message);
}
}
}
}
|
AppDomain nesnemiz bellekten kaldırıldığıdan
dolayı "Attempted to access an unloaded AppDomain (Bellekten kaldırılmış
bir AppDomaine erişmeye çalıştınız)" hatasını aldık.
Diğer bir AppDomaine assembly yüklemek.
Plugin örneğinde gerçekleştireceğimiz işlem dll lerin çalışma zamanında
ikinci bir AppDomain nesnesine yüklenmesidir.Bunu Activator sınıfını
kullanarak gerçekleştiriyoruz.
Activator.CreateInstanceFrom(
yenidomain, "c:\\Test.dll", "Test", false,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance,
null, new object[] { },
null, null, null).Unwrap();
|
CreateInstanceFrom metoduyla Test.dll
assembly sini yarattığımız yeni AppDomaine yüklüyoruz.Böylece
yenidomaini bellekten kaldırdığımızda yüklenen dll de kaldırılmış
oluyor.
Plugin tabanlı programlama
Evet geldik makalenin asıl konusuna.Geliştirdiğimiz uygulamaların esnekliğini,güncelleme
kolaylığını ve uyarlanabilirliğini en iyi Plugin teknolojisini kullanarak
sağlayabiliriz.Gerçek hayattan bir örnek vermek gerekirse, bir şirket yöneticisi
olduğunuzu düşünün.Şirkete araba gerekiyor.Arabayı şirkete alıp bütün
işlemlerini kendiniz takip edebilirsiniz veya bir araba kiralama şirketinden
araba kiralarsınız.Arabayı kendi şirketinizin üstüne alırsanız, bir üst
modele geçmek istediğinizde bütün işlemlerle siz uğraşmak zorunda
kalacaksınız.Arabayı kiraladığınız taktirde bu tür sorunlarla sizin
yerinize kiralama şirketi uğraşacaktır.Bir üst modele çok rahat bir şekilde
geçebileceksiniz.
İki ayrı yapımız olacaktır.Host uygulaması ve Plugin.Host uygulaması
plugin lerin yüklendiği yani bizim asıl uygulamamızdır.Plug in ise Host
uygulamamızda çalıştıracağımız kodu içerecektir.
Peki Host uygulamamıza yükleyeceğimiz Plugin lerin üye bilgilerine nasıl
ulaşacağız? Bu karışıklığı interface kullanarak çözebiliriz.Böylece
host uygulama,plug in den hangi metodları isteyeceğini bilir, plugin uygulaması
ise host uygulamasına hangi metodları sağlayacağını.
Plugin tabanlı uygulama geliştirirken
interface tasarımı önem teşkil etmektedir.Hatalı bir interface tasarımı
host uygulamasının tekrar derlenmesi ve tekrar dağıtımı demektir.Bu
sebepten dolayı interface tasarlanırken dikkat edilmelidir.
Örnek uygulama : yazıCan
Makale için geliştireceğim uygulama ve uygulamanın ismi konusunda karar
verememiştim.Murat Küçükosman arkadaşıma teşekkürü bir borç biliyorum.
Örnek uygulama olarak bir notepad uygulaması geliştireceğiz.Uygulayacağımız
plugin ler ise seçilen metin üzerinde bazı işlemler gerçekleştirip host
uygulamaya metni geri gönderecekler.
İşi daha da heyecanlı hale getirip, yazıCan uygulamamızda plugin leri
CodeDom ile çalışma zamanında yazıp derleyeceğiz.
İşe başlamadan önce plugin konusunda da önemine değindiğim interface
imizi geliştirelim.Host uygulama Plugin den neler bekleyecek plugin neler sağlayacak.
Host uygulamasında seçilen metnin plugin tarafından işlenip geri gönderileceğinden
bahsettik.Bunun için bir metodumuz olsun.String türünden parametre alsın ve
String türünden değer döndürsün.Böylece host ile plugin arasındaki ilişkiyi
belirlemiş olacağız.
IyaziCan.cs
|
using System;
using System.Collections.Generic;
using System.Text;
namespace yaziCanInterface
{
public interface IyaziCan
{
string ProcessValue(string TextValue);
}
}
|
Host ve Plugin projeleri ayrı projeler
olacağından dolayı ve bu iki proje de IyaziCan interfaceini kullanacağımızdan
dolayı IyaziCan interfaceini ayrı bir projede yaratmayı unutmayın.
Interface belirlendikten sonra uygulamamızı geliştirme işlemine geçebiliriz.Uygulamamız
notepad uygulaması olacağından dolayı bir WindowsApplication projesi olacaktır.Uygulamanın
yeni dosya açma,kaydet, farklı kaydet gibi kodlarını burda belirtmeyeceğim.Örnek
dosyasını indirerek bu kodlara erişebilirsiniz.
Host uygulamaya IyaziCan interface dosyasını referans göstermeyi unutmayın.
İlk ekranımıza bir göz atalım
(Form1)
Dosya menüsü altında standart işlemlerimiz
mevcut.
Araçlar menüsü altında Eklenti yönetimi,Plugin kodu yazma(yazıCan) ve
Eklentiler menüsünü yenile seçenekleri mevcut.
Eklentiler menüsünde ise uygulamamızda yüklü olan eklentiler mevcut.
Eklenti yönetimi
Bu formda eklenti dosyalarının yükleneceği klasör seçimi yapılmaktadır.Ayrıca
seçilen klasör altında mevcut olan eklenti dosyaları listelenmektedir.İstendiği
taktirde bu dosyalar Kaldır butonu ile silinebilmektedir.
yazıCan
İşi daha da heyecanlı hale getiren bu formda yazıCan uygulamasında
kullanacağımız eklentileri c# kullanarak kendimiz kodlayacağız.
Plugin geliştirirken dikkat etmemiz gereken IyaziCan interfaceini uygulamamız
ve Plugini yaratacağımız yeni bir AppDomaine yükleyeceğimizden dolayı
plugin sınıfının MarshalByRefObject sınıfından türemesidir.
yazıCan da seçilecek bir metni büyük harfe çeviren bir plugin yazalım.
Bunun için Araçlar menüsünden yazıCan seçeneğini seçin.Karşınıza
plugin kodunu yazacağımız ekran gelecektir.İşlemler menüsünden "yazıCan
Şablonu Uygula" şeçeneğini seçin.Gerekli kod ekrana yüklenecektir.
Plugin ismi BuyukHarf olsun.Aşağıdaki kodu yazalım.
İşlemler menüsünden Derle şeçeneğini
şeçelim.Ekranı kapattığımızda Eklentiler menüsü güncellenmiş olacaktır.
Hemen denemesini yapalım;
Ana ekranda bir yazı yazın ve yazının bellirli bir bölümünü seçin,
Eklentiler menüsünden BuyukHarf seçeneğini tıklayın.
Artık aynı yöntemi kullanarak
uygulamamıza KüçükHarf,Kırp gibi değişik fonksiyonlar kazandıracak
plugin leri yazıCan uygulamasında çalışma zamanında derleyip,
kullanabiliriz.
Örnekte değinmek istediğim son nokta Eklentiler menüsünde herhangi bir
eklenti seçildiğinde çalışacak kod hakkında;
try
{
AppDomain domain = AppDomain.CreateDomain("PluginDomain");
IyaziCan o1 = (IyaziCan)Activator.CreateInstanceFrom(
domain, strPluginFolder + @"\" + sender.ToString() + ".dll", sender.ToString(), false,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance,
null, new object[] { },
null, null, null).Unwrap();
this.rtb.SelectedText = o1.ProcessValue(this.rtb.SelectedText);
AppDomain.Unload(domain);
}
catch (Exception excp)
{
MessageBox.Show(string.Format("Eklenti çalıştırılırken {0} hatası oluştu.", excp.Message));
return;
}
|
Dikkat ederseniz
Activator.CreateInstanceFrom metodu ile ikinci AppDomaine yüklediğimiz
assembly nesnesini IyaziCan türünden o1 nesnesinde tutuyoruz.Bu şekilde plug
in metodlarını kolay bir şekilde görebiliyor ve kullanabiliyoruz.
Bu makalemde çalışma zamanında .Net kodu oluşturma/derleme ve Plugin tabanlı
uygulamalar hakkında bilgi vermeye çalıştım.
Umarım yararlı olmuştur.
Hepinize mutlu günler dilerim.
Örnek Uygulama
Levent YILDIZ
[email protected]
[email protected]
Makale:
CodeDom, AppDomain ve Plug-in Tabanlı Programlama C#, Visual C# ve .NET Levent Yıldız
|
|
|
-
-
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
|
|
|