C#nedir?com
 
YAZAR HAKKINDA
Burak Selim Şenyurt
Burak Selim Şenyurt
http://www.buraksenyurt.com
İletişme geçmek için tıklayın.
303 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: anahtar birlikte burada dikkat dynamic isimli kelimesi main(string[] metodu missingvalue parametre public static studio tipinden C# / VC#/.NET Burak Selim Şenyurt
 
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 : Orta
Kategori : C# / VC#/.NET
Yayınlanma Tarihi : 5/4/2009
Okunma Sayısı : 10323
Yorum Sayısı : 3     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.
Selman UZUN
Web Kameralı Basit Güvenlik Sistemi
Selman UZUN
yazının devamı >
Koray Kırdinli
C# ile Konfigürasyon Dosyaları
Koray Kırdinli
yazının devamı >
Turhal Temizer
Visual Studio 2010 – Microsoft Report Raporlarına Resim Ekleme
Turhal Temizer
yazının devamı >
Turhal Temizer
Silverlight Business Application – Nedir?
Turhal Temizer
yazının devamı >
Turhal Temizer
LINQ to SQL - JOIN
Turhal Temizer
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Tembel Yazılımcı'nın Seyir Defteri
Test Driven Development ve Unit Testing 7/8/2010
Burak Selim Senyurt(MVP)
Workflow Foundation Öğreniyorum - Ders 13 - Workflow Service için İstemci Geliştirmek 7/30/2010
Turhal Temizer 'in Blogu
SharePoint 2010–Virtual Machine ile Çalışmak 7/30/2010
Turhal Temizer 'in Blogu
İş Değişikliği–B/S/H Group 7/30/2010
Burak Selim Senyurt(MVP)
NedirTv?com Yeni Arayüzü ile Yayında 7/23/2010
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Her Yönüyle C# - Sefer Algan
C# 4.0 - Bizleri Bekleyen Yenilikler
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon
Uzun bir süredir (son bir senelik zaman dilimi içerisinde) C# 4.0 ile birlike gelen yeniliklerden haberdarız. Şöyle bir kaç sene öncesini hatırlıyorum da. :) Visual Studio 2005, Whidbey kod adı ile yayınlanmış ve C# 2.0 ile birlikte gelen pek çok yenilik olmuştu. Ancak bunlar içerisinde belkide en önemli olanı, CLR(Common Language Runtime) çekirdiğinde değiştirilme yapılmasını da zorunlu kılan generic mimariydi. Tabiki generic dışında gelen, yield anahtar kelimesi, isimsiz metodlar(anonymous methods), static sınıflar ve diğerleride önemli gelişmelerdi. Zaman ilerledi ve C# 3.0 ile birlikte bu kez hayatımıza, generic modelinden daha fazla etki yapan LINQ(Language INtegrated Query) girdi. Bir geliştirici olarak her zaman için yeniliklere açık olmamız ve yakalayabildiğimiz ölçüde takip etmemiz gerektiğini düşünüyorum. Bu bir geliştirici için neredeyse bir yaşam tarzı. Dolayısıyla artık C# 4.0 üzerinde konuşmanın zamanı geldide geçiyor.

C# 4.0 ile birlikte gelen yeniliklerin daha çok dinamik çalışma zamanını(Dynamic Language Runtime-DLR) kullanan diller üzerinde odaklanmış durumda olduğunu söyleyebiliriz. Peki bu ne anlama geliyor? DLR tarafını ilgilendiren dillere ait nesneler ile daha kolay konuşulması olarak küçük bir sebep belirtebiliriz. Bu nedenle C# 4.0 ile birlikte gelen önemli yeniliklerden birisi olan dynamic anahtar kelimesi sayesinde, Python, Ruby veya Javascript ile üretilen nesnelerin C# 4.0 tarafında late-binding ile ele alınması mümkün. Hatta var olan .Net nesnelerinin reflection kullanılmadan ele alınması veya COM objelerine ait üyelerin çağırılmasında bu anahtar kelimeyi kullanabiliyoruz. Aslında C#' ın 2.0, 3.0 versiyonunda gelen yenilikler nasıl ki belirli ihtiyaçlar nedeni ile ortaya çıkmışsa, C# 4.0 ile gelen yenilikleride bu anlamda düşünmemiz ve araştırmamız gerekiyor.

Bu yazımda sizlerle ilk olarak, dynamic kelimesi ile ilgili olan araştırmalarım sonucu elde ettiğim bilgileri paylaşıyor olacağım. İşe ilk olarak aşağıdaki şekilde görülen yapıya sahip olduğumuzu düşünerek başlayacağız.



Şimdi bu yapıyı kısaca açıklayalım. Commands isimli sınıf kütüphanesi(Class Library) IGraphic arayüzünü(Interface) uygulayan Circle ve Rectangle isimli sınıflara sahiptir.

IGraphic arayüzü

namespace Commands
{
    public interface IGraphic
    {
        void Draw();
    }
}
Circle sınıfı

using System;

namespace Commands
{
    public class Circle
        :IGraphic
    {
        #region IGraphic Members

        public void Draw()
        {
            Console.WriteLine("Circle...");
        }

        #endregion
    }
}

Rectangle Sınıfı

using System;

namespace Commands
{
    public class Rectangle
        :IGraphic
    {
        #region IGraphic Members

        public void Draw()
        {
            Console.WriteLine("Rectangle...");
        }

        #endregion
    }
}

Console Application tipinden olan uygulamamız, Commands isimli sınıf kütüphanesini referans etmekte olup başlangıçta aşağıdaki kod içeriğine sahiptir.

using Commands;

namespace CSharp4Features
{
    class Program
    {
        static void Draw<T>(T graphObject)
            where T : IGraphic
        {
            graphObject.Draw();
        }
        static void Main(string[] args)
        {
            #region Başlangıçtaki durumumuz

            Draw<Circle>(new Circle());
            Draw<Rectangle>(new Rectangle());

            #endregion
        }
    }
}

Uygulamayı çalıştırdığımızda aşağıdaki sonucu alırız.



Bu kod parçasında dikkat edilmesi gereken önemli noktalardan birisi, generic Draw<T> metodudur. Burada yer alan generic T tipine IGraphic arayüzünden türeme koşulu getirilmiştir. Bu sebepten dolayı, IGraphic arayüzünü uygulayan tüm tiplere ait Draw metodunu çağırmamızı sağlayan tek bir metod geliştirmiş oluyoruz. Dolayısıyla tek yapılması gereken, Draw<T> metodunun kullanıldığı yerde, doğru tipe ait(bu örnek için Rectangle veya Circle) nesne örneğini parametre olarak aktarmaktır.

Şimdi burada, bizi dynamic kelimesine götürecek bir veya bir kaç sebep arayacağız. İşte bir kaç blog içerisinde yakaladığım ortak soru geliyor...Ya Console uygulaması, IGraphic arayüzüne erişemiyor olsaydı. Bunu ayarlamak son derece kolay. Tek yapmamız gereken IGraphic arayüzünün public olan erişim belirleyicisini kaldırmak.(Bir başka deyişle internal'a çekmekki bu durumda söz konusu tipe sadece tanımlı olduğu assembly içerisinde erişilebildiğini hatırlayalım) Bu durumda Draw<T> metodumuz için derleme zamanı(Compile Time) hatası alınacaktır. Peki ne yapılabilir? Reflection tekniklerinden yararlanarak ilgili tipin Draw metodunun çağırılması sağlanabilir. Yani kodu aşağıdaki hale getirebiliriz.

using Commands;
using System.Reflection;

namespace CSharp4Features
{
    class Program
    {
        static void Draw<T>(T graphObject)
        {
            MethodInfo methodInfo = typeof(T).GetMethod("Draw");
            if (methodInfo == null)
            {
                System.Console.WriteLine("Method bulunamadı");
            }
            methodInfo.Invoke(graphObject, new object[0]);
        }

        static void Main(string[] args)
        {
            Draw<Circle>(new Circle());
            Draw<Rectangle>(new Rectangle());
        }
    }
}

İlk olarak typeof metodu ile T tipi elde edilmekte ve Draw isimli metod istenerek MethodInfo tipinden bir referansa aktarılmaktadır. Bilindiği üzere reflection mimarisinde, çalışma zamanında tipler ve üyelerine ait bilgiler elde edilmekte ve istenirse üyelerin yürütülmesi(örneğin metodların çağırılması) sağlanabilmektedir. Bu nedenle ilk olarak T tipinin çalışma zamanı referansı üzerinden Draw metodu elde edilmeye çalışılır. Sonrasında ise eğer MethodInfo referansı null değilse Invoke fonksiyonuna gerekli parametreler gönderilerek Draw metodunun icra edilmesi sağlanır. (Tabiki çalışma zamanında gelen T nesne örneğine ait olan Draw metodunun) Uygulamayı bu haliyle çalıştırdığımızda yine aynı sonuçları alırız.



Ancak tabiki metodun bu yeni halinde tip güvenliğinden(type-safety) bahsetmemiz mümkün değildir. T için herhangibir tip kullanılabilir.

Peki dynamic anahtar kelimesi burada nasıl bir yaklaşım sunmaktadır. İşte aynı metodun C# 4.0 için dynamic anahtar kelimesi ile yazılmış hali.

using Commands;
using System.Reflection;

namespace CSharp4Features
{
    class Program
    {    
        static void Draw<T>(T graphObject)
        {
            dynamic obj = graphObject;
            obj.Draw();
        }

        static void Main(string[] args)
        {
            Draw<Circle>(new Circle());
            Draw<Rectangle>(new Rectangle());
        }
    }
}

Bu seferde aynı çıktıyı alırız. Tabi burada dikkat edilmesi gereken bir kaç nokta vardır ve kodun kısalmış olması bunlardan birisi değildir ;) Öncelikli olarak Draw metodu, söz konusu Circle veya Rectangle nesne örneklerine çalışma zamanında bağlanmaktadır. Bu zaten bizim reflection tekniği ile yapmakta olduğumuz bir işlemdir. Diğer yandan .Net Reflector aracı yardımıyla üretilen uygulama koduna bakıldığında söz konusu metod için aşağıdaki IL çıktısının oluşturulduğunu görebiliriz.



private static void Draw<T>(T graphObject)
{
    object obj = graphObject;
    if (<Draw>o__SiteContainer0<T>.<>p__Site1 == null)
    {
        <Draw>o__SiteContainer0<T>.<>p__Site1 = CallSite<Action<CallSite, object>>.Create(new CSharpInvokeMemberBinder(CSharpCallFlags.None, "Draw", typeof(Program), null, new CSharpArgumentInfo[] { new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null) }));
    }
    <Draw>o__SiteContainer0<T>.<>p__Site1.Target(<Draw>o__SiteContainer0<T>.<>p__Site1, obj);
}
Görüldüğü gibi Draw<T> metodu içerisinde <Draw>o_SiteContainer0<T> isimli generic bir tipin kullanıldığını ve bununda IL(IntermediateLanguage) tarafına eklendiğini görmekteyiz. Bir başka deyişle derleme işleminden sonra yine reflection kullanılan kod parçaları içeriye dahil edilerek, Circle veya Rectangle tiplerinden olan nesnelerin Draw metodunun çağırılması sağlanmış oldu.

NOT : Burada dikkat edilmesi gereken önemli bir noktada şudur. Eğer Draw<T> metoduna, Circle ve Rectangle dışında bir tip atarsak(özellikle Draw metodu olmayan) bu durumda RuntimeBinderException tipinden bir istisna alırız.

Tabiki bu kısım ve detaylarını daha iyi kavramak için belki biraz daha zamana ihtiyacımız olacak. Ancak bu anahtar kelimenin tek kullanım şeklinin, reflection ile elde edilen tiplere ait üyelerin çağırılmasını kolaylaştırmak olmadığınıda belirtmek isterim. Öyleki, dynamic kelimesi ile COM objelerinin ve bu sayede unmanaged API' lerin dinamik olarak ele alınması mümkün olabilir. Hatta, JSON formatına sahip bir nesnenin dynamic kelimesi ile kolayca ele alınabileceğini söyleyebiliriz. Bu noktada Office API' sine ait nesnelerin dynamic kelimesi ile son derece etkili ve kolay kullanılabildiğini de belirtmek isterim. Üstelik işin içerisine yine C# 4.0 ile gelen opsiyonel ve isimlendirilmiş parametreler(Optional and Named Parameters) adlı yeniliklerinde girdiğini söyleyebilirim.

Özet olarak artık C# programlama dilinin, dinamik olarak türlendirilmiş tiplere ait nesnelerle daha kolay konuşabildiğini söyleyebiliriz.

Elbetteki C# 4.0 ile birlikte gelen başka yeniliklerde var. Bu yeniliklerde, diğerleri gibi belirli ihtiyaçlardan ortaya çıkmıştır. Şimdi bir süreliğine aşağıdaki kod parçasını göz önüne alalım.

using System;
using System.Reflection;
using Word=Microsoft.Office.Interop.Word;

namespace NewFeatures2
{
    class Program
    {
        static void Main(string[] args)
        {
            Word.Application wrdApp = new Microsoft.Office.Interop.Word.Application();           
            wrdApp.Visible = true;
            object fileNamePath = @"C:\Yeni Ozellikler.docx";
            object missingValue = Missing.Value;

            wrdApp
                .Documents
                .Open(ref fileNamePath, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue);
            Console.WriteLine("Kapatmak için bir tuşa basınız");
            Console.ReadLine();
        }
    }
}

İlk olarak şunu belirtmek isterim; bu basit Console uygulamasında Microsoft.Office.Interop.Word assembly' ına ait bir referans yer almaktadır.



Program, sistemde yüklü olan Yeni Ozellikler.docx isimli bir Word dosyasını açmak için gerekli kodları içermektedir. Bu Word dosyasının açılması içinse, Microsoft.Office.Interop.Word assembly' ından yaralanılmaktadır. Bu assembly aslında Word ile konuşabilmemizi sağlayan COM API'sini sarmalayan(Wrap) bir yönetimli(Managed) kütüpanedir. Kod içerisinden, Word dökümanına erişebilmek için Application tipinden bir nesne oluşturulmaktadır. Uygulamanın görünürlüğü Visible özelliği ile set edildikten sonra ise, Open metodundan yararlanarak ilgili Word belgesinin açılması sağlanmaktadır. Ancak bu kod parçasında geliştirici açısından bazı zorluklar olduğu rahatlıkla gözlemlenebilir.

1- Open metoduna ait 16 adet parametrenin tamamının girilmesi zorunludur. Aşağıdaki şekilde durumun sıkıcılığı gözler önündedir.



NOT : Burada Juval Lowy' nin IDesign şirketinde kullandığı ve pek çok şirket tarafından da benimsenen C# kodlama standartları aklıma geliyor. Buradaki belirttiği bir maddeyi hatırlıyorum. "Metodların argüman sayılarının 5 i geçmesinden kaçının. Eğer öyleyse struct tipini kullanın". ;) Burada bir COM API' sinin Wrap edilmiş kütüphanesi içerisindeki bir fonksiyonun parametre yapısının değiştirilemeyeceği fikri belleğimizi tamamıyla kaplayabilir. Tabi C# 3.0 sonrasında bir fırsat olabileceği de akıllara gelebilir. "Bir Extension metod yardımıyla Open metodu yerine bir alternatif geliştirebilir miyim? En azından parametre sayısını düşürmemizi kolaylaştıracak..." Bunu denemenizi öneririm.

2- Parametreler COM nesnesine iletildiğinden, dışarıdan yapılacak olan atamalarda object tipinin kullanılması gerekmektedir.

3- ref anahtar kelimesinin kullanılması zorunludur.

Gerçekte, Open metodu içerisinde işimize yarayan ve bizim için anlam ifade eden tek bir parametre yer almaktadır. O da açılmak istenen dosyanın adıdır. Diğer parametrelerinin hiçbirini kullanmadığımız halde yazmak zorunda olduğumuzu görüyoruz. Keşke sadece gerekli olanları yazsabilseydik; o zaman bu iş daha kolay olmazmıydı? :( Nitekim buradaki Open metodu haricinde, çok daha fazla sayıda argüman ile çalışabilen COM fonksiyonellikleri söz konusu olabilir. Böyle bir durumda tam olarak tüm parametreleri yazma zorunluluğu bir kenara dursun, bunların bütünün ne işe yaradığınında bilinmesi gerekir.

Sanırım bu cümlelerden zaten nereye varmak istediğimi anlatabilmişimdir. .Net in gelecek nesillerinin en büyük hedeflerinden birisi dinamik dillere ait nesneler ile konuşabilmek ve bunu mümkün olduğunca kolaylaştırmaktır. Bu noktada COM API' leri gibi nesnelerinde kullanımı söz konusudur. Aynen yukarıda geliştirdiğimiz örnekte olduğu gibi. Bu nedenle C# 4.0 içerisinde seçimlik parametre kullanımına izin veren geliştirmeler yapılmıştır(Optional Parameters). Buna göre yukarıdaki kod parçasını C# 4.0 stilinde aşağıdaki gibi geliştirebiliriz.

Optional Parameters ile

using System;
using System.Reflection;
using Word=Microsoft.Office.Interop.Word;

namespace NewFeatures2
{
    class Program
    {
        static void Main(string[] args)
        {
            Word.Application wrdApp = new Microsoft.Office.Interop.Word.Application();           
            wrdApp.Visible = true;           
            wrdApp.Documents.Open(@"C:\Yeni Ozellikler.docx");
            Console.WriteLine("Kapatmak için bir tuşa basınız");
            Console.ReadLine();
        }
    }
}

Bu kod parçası çalıştığında da aynı sonucu alırız. Yine Word belgesi açılacak ve içeriği görüntülenecektir. Hem kodun okunurluğu kolaylaşmıştır, hem de kısalmıştır. Diğer taraftan parametre değerini aktarırken ref kullanılmadığına dikkat etmemiz gerekiyor.(Ommit ref özelliği) Üstelik object tipinden değişken ataması yerine doğrudan dosya adresininin içeriğini gönderebildiğimizede dikkat edelim.

Tabi ihtiyaçlar bitmek bilmiyor. Burada görüldüğü gibi gereksiz olan parametrelerin hiç biri bildirilmemiştir. Ayrıca ref anahtar kelimeside herhangibir şekilde kullanılmamıştır. Ancak arada başka bir parametrenin daha kullanılması gerekirse... :( Söz gelimi 3ncü parametre dosyanın yanlız okunabilir(ReadOnly) modda açılıp açılmayacağını belirtir. Optional Parameter tekniğini kullanırsak ikinci parametreyi atlamamız mümkün olmayacaktır. Acaba böyle bir vakada kodu yine istemediğimiz şekliyle aşağıdaki gibi geliştirmemiz mi gerekir?

using System;
using System.Reflection;
using Word=Microsoft.Office.Interop.Word;

namespace NewFeatures2
{
    class Program
    {
        static void Main(string[] args)
        {
            Word.Application wrdApp = new Microsoft.Office.Interop.Word.Application();           
            wrdApp.Visible = true;           
            object fileNamePath = @"C:\Yeni Ozellikler.docx";
            object missingValue = Missing.Value;
            object onlyRead = true;

            wrdApp
                .Documents
                .Open(ref fileNamePath, ref missingValue, ref onlyRead, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue);          

            Console.WriteLine("Kapatmak için bir tuşa basınız");
            Console.ReadLine();
        }
    }
}

Oysaki C# 4.0 bu gibi durumlar için isimlendirilmiş parametre(Named Parameters) kullanımını olanaklı kılmaktadır. Aşağıdaki şekilde görüldüğü gibi, intellisense' de bize yardımcı olmaktadır.



Dolayısıyla yukarıdaki kod parçasını şu şekilde geliştirebiliriz;

Named Parameters kullanımı ile

using System;
using System.Reflection;
using Word=Microsoft.Office.Interop.Word;

namespace NewFeatures2
{
    class Program
    {
        static void Main(string[] args)
        {
            Word.Application wrdApp = new Microsoft.Office.Interop.Word.Application();           
            wrdApp.Visible = true;
           
            wrdApp.Documents.Open(@"c:\Yeni Ozellikler.docx", ReadOnly: true);

            Console.WriteLine("Kapatmak için bir tuşa basınız");
            Console.ReadLine();
        }
    }
}

Son olarak Platform Interop Assembly(PIA) ile ilgili gelen yeniliklerden birisine değinmek istiyorum. Normal şartlarda Visual Studio 2010 öncesinde bir COM API' sini uygulamaya referans ettiğimizde, sarmalanan kütüphanenin özelliklerinde aşağıdaki şekilde görülen Embed Interop Types isimli bir kriter olmadığı bilinmektedir.



Oysaki Visual Studio 2010 ile birlikte bu özellikte gelmektedir. Bu tabiki sadece C# 4.0 diline bağlanacak bir yetenek olarak düşünülmemelidir.

Peki ne işe yarar? Eğer yukarıda geliştirdiğimiz C# 4.0 örneğinin ildasm(Intermediate Language DisAsseMbler) çıktısına bakacak olursak aşağıdaki durum ile karşılaşırız.



Göze çarpan özel bir nokta yer almamaktadır. Ancak Microsoft.Office.Interop.Word assembly' ının özelliklerinde yer alan Embed Interop Types seçeneğini true olarak değiştirir ve söz konusu uygulamanın IL çıktısına tekrardan bakarsak aşağıdak sonuçlarla karşılaşırız.



Görüldüğü gibi API içerisinde yer alan tipler, .Net programı içerisine birer tip olarak gömülmüştür. Aslında bu yenilik, PIA' ların, geliştirilen asıl uygulama içerisine tip bazında gömülerekten taşınabilmelerini kolaylaştırıcı bir özellik olarak görülebilir. Bu konudaki araştırmalarıma devam ediyorum. Yeni bilgiler kazandıkça sizlerle paylaşmaya devam ediyor olacağım. Böylece geldik bir makalemizin daha sonuna. Bu makalemizde sizlere C# 4.0 ile birlikte gelen bir kaç yeniliği aktarmaya çalıştım. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

NOT: Örnekler 2008 PDC'de yayımlanmış olan Visual Studio 2010 PreBeta sürümü üzerinden geliştirilmiştir. Yeni çıkacak sürümlerde hem anlatılan konularda hemde Visual Studio ortamında farklılıklar olabilir.

Burak Selim ŞENYURT
MVP (Connected System Developer-2008,C# 2007,2006)

Makale:
C# 4.0 - Bizleri Bekleyen Yenilikler C#, Visual C# ve .NET Burak Selim Şenyurt
  • Yazılan Yorumlar
  • Yorum Yaz
ŞUB
9
2010
Mükemmel bir anlatım.Tebrikler.Makaleleriniz sanki sınırsız gibi.Tekrar teşekkürler.
AĞU
11
2009
Hocam,makaleleriniz sayesinde çok şey öğrendim. En büyük yardımcınsınız. Hiç görüşmedik ama bilmenizi isterim ki çok büyük emeğiniz var bende. Elinize sağlık.
MAY
10
2009
Olayın özü bundan daha iyi anlatılamazdı bence. Teşekkürler
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