İlkay İlknur

just a developer...

C# Fundamentals - Object & Collection Initializers

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

C# Fundamentals - Object & Collection Initializers

C# Fundamentals serisinin bu videosunda Object & Collection Initializers konusuna değiniyoruz. LINQ sorguları yazarken özellikle object initializersları bolca kullanacağımız için LINQ konusuna giriş yapmadan önce bu konuyu inceliyoruz.

Videoları kaçırmamak için youtube kanalıma üye olabilirsiniz veya mail ile bloga yazı eklediğimde haberdar olabilirsiniz.

Bir sonraki videoda görüşmek üzere...



Roslyn Syntax Tree API'larına Giriş

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Daha önce .NET Compiler Platform (Roslyn) ile ilgili yazdığımız tüm yazılarda ve videolarda Roslyn projesinin derleyicileri bir kara kutu olmaktan çıkardığından ve artık bizim de derleyicilerin kullandığı yapıları kullanıp elimizdeki kodu analiz edebileceğimizden çokca bahsetmiştik.

Bugün bu konuya syntax tree API'ları ile giriş yapacağız. Yazdığımız kodlar derleme işlemi sırasında ilk olarak derleyici tarafından parse edilirler ve bu işlemin sonucunda bir syntax tree oluşturulur. Bu syntax tree içerisinde yazmış olduğumuz kod içerisindeki herşey hiyerarşik bir şekilde tutulur.

Örneğin, aşağıdaki gibi son derece basit bir kodumuz olduğunu düşünelim.

class C
{
    public void M()
    { }
}

Bu kod derleyici tarafından derlendiğinde aşağıdaki gibi bir syntax tree oluşturulur.

Gördüğümüz gibi yazmış olduğumuz kod içerisinde bulunan her bir tanımlama, boşluk, keyword vb... tüm bileşenler syntax tree içerisinde eksiksiz tutuluyor. Syntax tree'ler derleme aşamasının en önemli yapılarından biri. Çünkü kod içerisindeki tüm bileşenler syntax tree içerisinde düzenleniyor ve kategorilere ayrılıyor. Derleme işlemi sırasında parserdan sonraki adımlarda da bu aşamada üretilen syntax tree kullanılıyor.

Derleyici tarafından yaratılan syntax tree içerisinde 3 farklı tipte eleman bulunuyor.

  • Syntax Node
  • Syntax Token
  • Syntax Trivia

Syntax Node'lar kod içerisindeki tanımlamaları,ifadeleri, koşul ifadeleri vb... dil içerisinde temel yapıları temsil ederler. Örneğin class tanımlaması en tepede bir syntax node ile ifade edilir. Roslyn içerisinde her yapıya özel SyntaxNode tipinden türetilmiş özel SyntaxNode sınıfları vardır. Yukarıdaki syntax tree resminde mavi olan nodelar birer syntax node'dur.

Syntax Token'lar yine dil içerisinde bulunan en ufak bileşenleri temsil eden yapılardır. Syntax tokenların tree içerisinde altında hiçbir zaman başka tokenlar veya syntax node'lar bulunmaz. Roslyn içerisinde SyntaxToken'lar için tek bir tip bulunurken bu tip içerisindeki Kind propertysi ile token tipleri birbirinden ayrıştırılabilir. Yukarıdaki syntax tree resmindeki yeşil renkli nodelar syntax tokendır.

Syntax Trivia'lar da kod içerisinde bulunan ancak derleme işlemi için çokta büyük anlam ifade etmeyen bileşenler için kullanılır. Bu bileşenler kod içerisindeki yorumlar, boşluklar gibi yapılardır. Syntax trivia'lar syntax tokenlara bağlıdırlar. Her bir syntax token'ın LeadingTrivia ve TrailingTrivia collectionları vardır. Bu collectionlar ile token'a bağlı olan trivia'lara erişilebilir.

Bu kadar teori şimdilik yeterli :) Şimdi hemen bir console uygulaması açalım ve bu API'ları nasıl kullanacağımıza bakalım.

Projemizi yarattıktan sonra yapmamız gereken ilk şey Microsoft.CodeAnalysis nuget paketini yüklemek.

Install-Package Microsoft.CodeAnalysis 

Bu işlemi de gerçekleştirdikten sonra artık hazırız. Varolan bir kodun syntax tree'sini çıkarabilmek için Microsoft.CodeAnalysis.CSharp namespace'i içerisinde CSharpSyntaxTree tipinin ParseText metodunu kullanacağız. Bu metot string olarak kendisine verilen bir kodun syntax treesini verir.

class Program
{
    static void Main()
    {
        var tree = CSharpSyntaxTree.ParseText(@"class C
        {
            public void M()
            { }
        }"
);
    }
}

ParseText metodunu çağırdıktan sonra artık elimizde bir syntax tree var. Bu syntax tree üzerinde istediğimiz elemanlara ulaşabiliriz ve ağaç üzerinde gezebiliriz. İlk olarak yaratılan veri yapısı bir ağaç olduğu için ağacın root elemanına ulaşalım.

class Program
{
    static void Main(string[] args)
    {
        var tree = CSharpSyntaxTree.ParseText(@"class C
        {
            public void M()
            { }
        }"
);

        var root = tree.GetRoot();
    }
}   

Ağacın rootuna ulaştıktan sonra artık ağaç içerisindeki her bir elamana da rahatlıkla ulaşabiliriz. Örneğin basit bir LINQ sorgusuyla tüm metot tanımlamalarına ulaşmamız mümkün.

class Program
{
    static void Main(string[] args)
    {
        var tree = CSharpSyntaxTree.ParseText(@"class C
        {
            public void M()
            { }
        }"
);

        var root = tree.GetRoot();
        var methods = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
        foreach (var method in methods)
        {
            Console.WriteLine(method.ToString());
        }
    }
}

Bu kod çalıştığında parse ettiğimiz kod içerisinde tek metot olduğu için ve o metot da M metodu olduğu için M metodu doğrudan console'a yazılacak.

Olayı biraz daha karmaşıklaştıralım ve parametre kabul eden metotların listesini çıkaralım.

class Program
{
    static void Main(string[] args)
    {
        var tree = CSharpSyntaxTree.ParseText(@"class C
        {
            public void M()
            { }
            public void M2(int a)
            { }
            public void M3(int a,string b)
            { }
        }"
);

        var root = tree.GetRoot();
        var methods = root.DescendantNodes().OfType<MethodDeclarationSyntax>().Where(t => t.ParameterList.Parameters.Any());
        foreach (var method in methods)
        {
            Console.WriteLine(method.ToString());
        }
    }
}

Parse ettiğimiz koda baktığımızda yazdığımız kodun çıktısının M2 ve M3 metotları olması lazım. Hemen kodu çalıştırıp sonucunu görelim.

Şimdi eminim aklınıza takılan şöyle bir sorun var. Bu sorguları bu şekilde iyi güzel yazıyoruzda metot tanımlamalarının MethodDeclarationSyntax tipinde olduğunu veya parametrelerin bu tip içerisindeki ParameterList.Parameters collectionında tutulduğunu nasıl bileceğiz ? Bu konu tabi sadece bizim değil aynı zaman da Roslyn'i ve Roslyn-Visual Studio entagrasyonunu yazan ekibin de bir sorunuydu zamanında. Bu nedenle geliştirdikleri bir araçla bu sorunu çözdüler. Şimdi bu araç artık Visual Studio içerisinde extension olarak sunuluyor.

Syntax Visualizer dediğimiz pencere yardımıyla istediğimiz kodun syntax treesini herhangi bir kod çalıştırmadan görebiliriz ve her bir elemanın tüm propertylerine de ulaşabiliriz. Bu extensionı yüklemek için .NET Compiler Platform SDK'ini yüklememiz gerekiyor. Bu extension aynı zamanda Roslyn API'larıyla yaptığımız kod analizlerini Visual Studio extensionı olarak yayınlamamız sağlayan templateları da sağlıyor. Extensionı kurmak için buradan VS Gallery'e gidebilir veya Visual Studio içerisiden Tools => Extensions and Updates menüsü üzerinde .NET Compiler Platform SDK'ini yükleyebilirsiniz.

Extension'ı yükledikten sonra View => Other Windows => Syntax Visualizer adımlarıyla Syntax Visualizer'ı açabilirsiniz.

Parse ettiğimiz kodu da Visual Studio içerisine kopyalarsak aşağıda gördüğünüz gibi hızlı bir şekilde elemanlara ulaşabilir ve propertylerini hızlı bir şekilde kontrol edebiliriz.

Bu yazımızda syntax tree API'larını kısa bir giriş yaptık ve LINQ ile syntax tree üzerinde elemanlara nasıl erişilebiliriz konusunu inceledik. Bir sonraki yazıda syntax tree üzerinde dolaşmanın farklı bir yolunu inceleyeceğiz.

Görüşmek üzere...



C# Fundamentals - Declarative Programlama Nedir ?

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

C# Fundamentals serisinde LINQ konusuna başlarken ilk olarak declarative programlama konusuna değiniyoruz. Declarative programlama nedir, C# içerisindeki örnekleri nelerdir gibi konulara cevap arıyoruz.

Bu video ile beraber artık LINQ konusuna giriş yaptık ve genel olarak LINQ, C# içerisinde hangi programlama paradigmasını sağlıyor gördük. Sıradaki videolar ise LINQ sorguları yazarken kullanmamız gereken bazı kavramlarla ilgili olacak. Videoları kaçırmamak için youtube kanalıma üye olabilirsiniz veya mail ile bloga yazı eklediğimde haberdar olabilirsiniz.

Bir sonraki videoda görüşmek üzere...



C# Fundamentals - Generics Serisi

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Bundan yaklaşık 2 yıl önce "C# Fundamentals" isimli bir video serisi yaratmak istemiştim. Bu serinin amacı zaman zaman aldığım "hiç C#'ı yeni öğrenenler için birşeyler yapmıyorsun"'a biraz da olsa cevap vermekti :) Her ne kadar zaman zaman üniversitelerde ve Açık Akademi Yaz Okulununda bu içerikleri sunsam da bir türlü blogda veya başka bir yerde bunları birleştirip paylaşamadım. Zaman geçti ama malesef ilk videodan sonra da devamını getiremedim.

Geçtiğimiz hafta her zaman aklımda olan bu tarafı devam ettirmeye karar verdim ve çektiğim videolarla C#'ta Generic'ler konusunu tamamladım. 4 video içerisinde genericlerin ne işe yaradığı, genericler olmadan nasıl sıkıntılarla karşılaştığımızı, generic tiplerin nasıl yazıldığını ve kullanıldığını, son olarak ise generic kısıtlayıcıların nasıl kullanılacağını bulabilirsiniz.

Bu tür videoları blogda tek tek paylaşmak yerine seriyi bitirdikten sonra blog üzerinden paylaşmayı planlıyorum. Bu nedenle videolardan hemen haberdar olmak isterseniz Youtube kanalıma üye olup yeni video yayınlandığında anında haberdar olabilirsiniz.

C# Fundamentals serisinde olmasını istediğiniz konuları bu yazının altına yorum olarak yazabilir veya mail(ilkay@ilkayilknur.com) ile doğrudan bana iletebilirsiniz.

C# Fundamentals - Generics Serisi Videoları

Generic Tiplerin Olmadığı Bir Dünya

Generic Tipler Nasıl Kullanılır ?

Kendi Generic Tiplerimizi Nasıl Yazarız ?

Generic Constraints (Kısıtlayıcılar)



Typescript Development Araçları

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Typescript Development Araçları

Bir önceki yazımızda "Typescript Nedir ?" konusuna değinmiştik. O yazıda örneklerimizi online bir araç olan Typescript Playground'u kullanarak gerçekleştirmiştik. Bu yazımızda Typescript ile uygulama geliştirmek istediğimizde bilgisayarımızda kullanabileceğimiz araçları inceleyeceğiz. Zaman kaybetmeden ilkiyle başlayalım.

Visual Studio 2015 & 2013

Visual Studio kullanarak Typescript ile uygulamalar geliştirebiliyoruz. Visual Studio 2013 için bir extension yüklemek gerekirken Visual Studio 2015 ile bu extension default olarak kurulu geliyor. Ayrıca ücretsiz olarak kullanabileceğiniz Visual Studio Community Edition ile de Typescript development yapmak mümkün.

Yukarıda bahsettiğim Visual Studio sürümlerinden herhangi birini bilgisayarınıza kurduğunuzda yeni bir project yaratmak istediğinizde diğer diller seçeneğinde artık Typescript'i de görüyor olacaksınız.

"HTML Application with Typescript" proje tipi üzerinden yeni bir proje yaratırsanız doğrudan Typescript'in sağladığı tüm yeteneklere ve özelliklere erişiminiz olacaktır.

Eğer hali hazırda bir javascript kodunuz varsa solution içerisine bir Typescript dosyası eklediğinizde Visual Studio projenize otomatik olarak Typescript desteği ekleyecektir.

NPM ile Typescript Compilerını Yükleme

Bundan sonra bahsedeceğimiz Visual Studio haricindeki alternatifleri kullanmadan önce bilgisayarımıza NPM üzerinden Typescript compilerını kurmamız gerekiyor. Çünkü Visual Studio bu kurulumları otomatik olarak yaparken diğer alternatifler için bizim kurulum işlemini manuel olarak yapmamız gerekiyor. Eğer bilgisayarınızda NPM yok ise öncelikle https://nodejs.org/ üzerinden bilgisayarımıza uygun nodejs sürümünü yüklememiz gerekiyor. Sonrasında da aşağıdaki commandi kullanarak Typescript compilerını bilgisayarımıza yükleyebiliriz.

npm install -g typescript 

Geçtiğimiz -g parametresi Typescript'i global olarak bilgisayarımıza kurmamızı sağlıyor. Typescript compilerını bu şekilde bilgisayarımıza kurduktan sonra alternatif geliştirme araçlarını artık kullanabiliriz.

tsconfig.json

Yine bundan sonra araçları kullanırken mutlaka kullanamamız gereken yapılardan biri de tsconfig.json dosyası. tsconfig.json dosyası Typescript compilerına derleme ile ilgili bir takım bilgileri iletmemizi sağlıyor. Derleyeceğiniz Typescript dosyalarının bulunduğu klasörün root'una tsconfig.json dosyası koyarsanız Typescript compilerı da buradaki bilgiler doğrultusunda Typescript kodlarınızı Javascript'e çevirecektir.

tsconfig.json dosyasının içerisini kısaca incelersek, aslında karşımıza compilerOptions, files ve exclude isminde üç farklı alan çıkıyor. files alanı Typescript compilerının klasör içerisinde sadece belirtilen Typescript dosyalarının derlenmesini sağlıyor. exclude alanı ise files'ın tam tersi olarak belirtilen dosyaların veya klasörlerin Typescript compilerı tarafından derlenmemesi gerektiğini belirtiyor. Bu iki alan da opsiyonel alanlar. Yani bu alanların ikisini de boş geçerseniz Typescript compilerı klasör içerisindeki bütün Typescript dosyalarını derleyecektir.

compilerOption alanı ile de derleyeciye derleme operasyonu ile ilgili direktifler verebiliyoruz. Örneğin Typescript kodlarının Ecmascript 5 versiyonuna göre çevrilmesi veya çevrilirken commentlerin silinmesi gibi pek çok farklı direktifi bu alandan compilera iletebiliyoruz. tsconfig.json dosyasında bulunan tüm alanlarla ile ilgili detaylı bilgiyi burada bulabilirsiniz.

Aşağıda örnek bir tsconfig.json dosyası bulabilirsiniz.

{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"out": "../../built/local/tsc.js",
"sourceMap": true
},
"files": [
"core.ts",
"sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
"checker.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
"tsc.ts",
"diagnosticInformationMap.generated.ts"
]

Visual Studio Code

Windows, Mac ve Linux platformlarında kullanabileceğimiz ücretsiz alternatiflerden biri de Visual Studio Code.

Visual Studio Code'u yüklediğinizde .ts uzantılı dosyaları açtığınızda otomatik olarak ilgili intellisense ve development kolaylıkları size sağlanıyor. Eğer birden fazla Typescript dosyanız varsa ve bunları birbirlerine referans alıp kullanmak isterseniz öncelikle çalıştığınız klasör içerisine tsconfig.json dosyasını eklemeniz gerekiyor.

Sonrasında ise Shift+Alt+B'ye basarak derleme işlemini başlatıyoruz.

Configure Task Runner seçeneğine basarak devam ediyoruz. Sonrasında klasör içerisine tasks.json isimli bir dosya ekleniyor. Burada Visual Studio Code bizim klasör içerisindeki dosyalarımızı nasıl derleyeceği ile ilgili bilgileri tutuyor. Biz Typescript kullandığımız için aşağıda gördüğünüz üzere Typescript compilerının nasıl çağırılacağı ile ilgili detaylar bu dosya içerisinde tutuluyor. Bu dosya içerisindeki args kısmını siliyoruz. Çünkü yaratılan template içerisindeki örnek olması açısından bir dosya adı eklenmiş. Biz bunu silerek devam ediyoruz. Çünkü derlenecek olan dosyaların adını zaten tsconfig.json dosyası içerisinde vermiştik.

tasks.json dosyasını kaydettikten sonra tekrar Shift+Alt+B'ye basıyoruz ve klasörümüz içerisindeki Typescript dosyalarını derliyoruz. Derleme işlemi bittikten sonra sol tarafta .js uzantılı dosyaların oluştuğunu göreceksiniz.

Sublime Text

Sublime Text de yine Visual Studio Code gibi Mac, Windows ve Linux platformlarında kullanabileceğimiz alternatif araçlardan biri.

Eğer bilgisayarınızda Sublime Text kurulu değilse buradaki adresten kurulumu yapıp sonra da Package Manager'ı Sublime Text'e kurmanız gerekiyor. Bu kurumları yaptıktan sonra package control üzerinden Typescript extensionını Sublime Text'e yükleyebilirsiniz.

Package Control --> Install Package --> TypeScript 

Bu adımları tamamladıktan sonra Ctrl+B ile Typescript dosyalarınızı derleyebilirsiniz. Tabi öncelikle çalıştığınız ana klasör içerisine yukarıda bahsettiğim tsconfig.json dosyasını koymanız gerekiyor.

Notepad :)

Son olarak bahsetmek istediğim alternatif ise Notepad :) Tabi Notepad içerisinde herhangi bir şekilde intellisense vs.. gibi güzellikleri kullanmamız mümkün değil. Ancak diyelim ki mevcut bir Typescript kodunuz var ve hızlı bir şekilde ufak bir değişiklik yapacaksınız. Herhangi bir editör vs.. gerek kalmadan değişikliği yapıp commandline üzerinden derleyip sonucunu görebilirsiniz.

Notepad'le veya herhangi bir editörle değişiklik yaptınız diyelim. Hemen tsconfig.json dosyasının bulunduğu klasörünüzün rootuna commandline'ı kullanarak gidin. Sonrasında da tsc commandini çalıştırın. Bu komutu çalıştırdıktan sonra Typescript compilerı klasör içerisindeki Typescript dosyalarınızı tsconfig.json'daki bilgilere göre derleyecektir.

Hatta ufak bir ipucu da veriyim. Eğer tsc commandine ek olarak -w parametresini geçerseniz, üzerinde değişiklik yaptığınız dosya her değiştiğinde Typescript compilerı değişiklik yapıldığını algılar ve otomatik olarak tekrardan derleme işlemini arka planda otomatik olarak yapar.

Gördüğünüz gibi Typescript ile geliştirme yapmak için kullanabileceğiniz pek çok farklı ortam var. İster bir C# developer olun ister front-end developer olun iki taraftan da aşina olduğunuz ve günlük yaşantınızda kullandığınız araçları işletim sistemi kısıtlaması olmadan kullanarak Typescript kodu yazıp derleyebilirsiniz.

Bir sonraki yazıda görüşmek üzere...



Typescript Nedir

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Evet bu yazımızın konusu "Typescript nedir ?". Typescript yeni bir programlama dili değil belki ancak bu yazıda istedim ki bilmeyenler için kısaca bir özet geçelim, bilenler ve kullananlar için de bilgi tazelemesi olsun.

Son yıllarda eminim ki Javascriptin önlenemez bir şekilde yükselişini farketmişinizdir. Javascript artık sadece browserda istemci tarafında işler yapmak için kullandığımız bir dil olmaktan çok daha farklı bir yerde. NodeJS gibi platformlarla artık Javascript serverda da çalışabiliyor. İstemci tarafında çalışan büyük masaüstü uygulamaları geliştirmek de artık Javascript ile mümkün. Bakınız electron.js.

Gördüğünüz gibi aslında başlarda sadece browserda çalışan bir programlama dili olarak tasarlanan Javascript zaman geçtikçe çok daha farklı ve tahmin edilemez bir noktaya ulaştı. Javascript'in ilk tasarlandığı zamanlarda büyük ölçekli uygulamalar geliştirmek için kullanılması çok da planlanmadığından aslında içerisinde büyük ölçekli uygulamalar geliştirirken bize oldukça yardımcı olan classlar, modüller, interfaceler vb.. yapıları da içerisinde bulundurmuyordu. Bu nedenle büyük ölçekli uygulamaları Javascript ile geliştirmek ve geliştirdikten sonra bu uygulamaların bakımını yapmak çokta kolay değil.

Javascript programlama dili aynı zamanda dinamik bir dil. Dinamik olması ona büyük bir güç katarken aynı zamanda development esnasında da bize bir o kadar zorluk çıkarıyor. Kod içerisindeki hataları bulmamız ve kodun bakımını yapmamız zorlaşıyor. Statik programlama dillerinin(C#,Java vb..) development esnasında bize sağladığı güzellikleri (refactoring, find references vb..) düşünürsek Javascript doğası gereği bu yeteneklerden de mahrum kalıyor. Eğer 100-200 satırlı bir kod yazıyorsanız bu eksiklikler size çok kritik gelmese de 10000-20000 satırlık bir uygulama yazıyorsanız emin olabilirsiniz ki bu özellikler size büyük zaman kazandıracaktır.

İşte Typescript'in amacı da aslında yukarıda bahsettiğim Javascript'in sıkıntılı yanlarından bizi kurtarak büyük ölçekli uygulamalar geliştirmemizi sağlamak. Bu nedenle Typescript aslında Javascript'in bir üst kümesi olarak konumlanıyor. Yani Javascript'in sahip olduğunu yapıların daha fazlasını içerisinde barındırıyor. Ayrıca Typescript statik bir dil olduğu için statik programlama dillerinin sahip olduğu yeteneklere de sahip oluyorsunuz.

Typescript kodu derlendiğinde çıktı olarak Javascript kodu üretiliyor. Yani Typescript içerisinde kullandığımız enum, interface gibi yapılar geçerli bir Javascript koduna çevriliyor. Kodumuzun düzenini sağlamak için kullandığımız bazı yapılar ise(örneğin interfaceler) Javascripte bile çevrilmiyor. Onlar sadece derleme işlemi sırasında Typescript tarafından kullanılıyor. Böylece temiz bir Javascript çıktısı elimizde bulunuyor. Ayrıca Typescript sadece derleme esnasında görev aldığı için çalışma zamanında Typescript'ten doğabilecek bir performans sorunu da söz konusu değil. Çünkü Typescript kodu derlenip Javascript kodu üretildiğinde Typescript'in işi burada bitiyor. Bunun yanında dışarıya çıkan kod tamamen Javascript olduğu için Typescript kullandığınız için herhangi ekstra bir runtime veya kütüphane vs.. kullanmanız gerekmiyor.

Bu kadar teorik bilgi sanırım yeterli. Şimdi istiyorsanız kısaca bir Typescript'e göz atalım. Örnek yapabilmek için hızlıca Typescript Playground'u kullanacağız. Typescript Playground, online olarak Typescript'i denememizi ve örnek yapabilmemizi sağlayan bir ortam. Sol tarafa Typescript olarak yazdığımız kodun Javascript'e çevrilmiş halini anında sağ tarafta görebiliyoruz. Unutmadan bahsediyim Typescript Playground da Typescript kullanılarak geliştirilmiş.

Typescript'in Javascript'in bir üst kümesi olduğundan bahsetmiştik. Yani yazdığımız Javascript kodları aynı zamanda geçerli bir Typescript kodu. Dolayısıyla Typescript içerisinde alışık olduğunuz gibi Javascript yazabilirsiniz veya elinizde daha önceden yazılmış Javascript kodları varsa bunları Typescript içerisinde kullanabilirsiniz. Eğer aşağıdaki kodu playground'a kopyalarsanız Typescript'in kodu başarılı bir şekilde derlediğini göreceksiniz.

var button = document.createElement('button');
button.textContent = "Hello";
button.onclick = function () {
    alert("Hello Typescript !");
};

Örneği biraz daha geliştirelim. Örneğin Typescript içerisinde OOP dillerinde olduğu gibi classlar kullanabiliyoruz.

class Hello {
    WriteHelloWorld() {
        alert("Hello World");
    }
}

var hello = new Hello();
hello.WriteHelloWorld();

Typescript tarafından da bu kod aşağıdaki gibi Javascript'e çevriliyor. Dolayısıyla biz classlar üzerinden operasyonlarımızı daha kolay bir şekilde yönetirken Typescript işin Javascript tarafıyla kendisi ilgileniyor.

var Hello = (function () {
    function Hello() {
    }
    Hello.prototype.WriteHelloWorld = function () {
        alert("Hello World");
    };
    return Hello;
})();
var hello = new Hello();
hello.WriteHelloWorld();

Typescript sahip olduğu statik programlama yetenekleri nedeniyle kod yazarken bize tanımladığımız değişkenlerle ilgili tip bilgisi verebiliyor. Aynı zamanda hatalı bir kod yazdığımızda da bu hatayı runtime sırasında değil kodu yazma esnasında alıyoruz. Belki de bu Typescriptin sağladığı en güzel fayda diyebiliriz.

Gördüğünüz gibi Typescript Javascript kodu yazmak istediğimizde işimizi oldukça kolaylaştırıyor. Bu yazı yazıldığı sıralarda Typescript 1.7 versiyonunda ve hızla 2.0 versiyonuna doğru ilerliyor. Pek çok büyük projede şu an Typescript etkin bir şekilde kullanılıyor. Mesela Angular 2 projesi şu an Typescript kullanılarak geliştiriliyor. Yani geleceği oldukça parlak bir programlama dili. Eğer şimdiye kadar hiç duymadıysanız veya kullanmadıysanız bir gözatmanızda fayda var derim. İleride eminim bir şekilde karşınıza çıkacaktır. ;)

Bir sonraki yazıda görüşmek üzere.



Roslyn Scripting APIs

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Bir önceki yazımızda Visual Studio 2015 Update 1 ile gelen Interactive Window'u incelemiştik. Interactive Window ile C# kodlarını Visual Studio içerisinde hızlı bir şekilde çalıştırıp anında sonuçlarını görebiliyoruz. Nasıl browserda console içerisinde script çalıştırıp sonucunu anında görebiliyorsak aynısını artık C# için de yapabiliyoruz. Peki bu nasıl mümkün oluyor ?

Aslında tüm sihir Roslyn'in scripting API'larında. Yani Interactive Window içerisinde bir kod yazdığınızda bu kod scripting API'ları aracılığıyla Roslyn'e gönderiliyor ve arkada derlenip, çalıştırılıp sonucu bize geri veriliyor. Şimdi isterseniz gelin bu scripting API'larına biraz gözatalım.

Scripting API'larına ulaşabilmemiz için projemize ilk olarak Microsoft.CodeAnalysis.Scripting nuget paketini yüklememiz gerekiyor.

PM> Install-Package Microsoft.CodeAnalysis.Scripting 

Nuget paketini yüklediğimiz proje eğer .NET Framework 4.6'yı target etmiyorsa aşağıdaki hatayı alıyoruz. Bu hatayı almamak için projemizi .NET Framework 4.6'ya yükseltmemiz gerekiyor.

Could not install package 'System.Runtime 4.0.20'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.5.2', but the package does not contain any assembly references or content files that are compatible with that framework

Nuget paketini başarılı bir şekilde yükledikten sonra artık scripting API'larını test etmeye hazırız. Genel olarak C# kodlarını çalıştırmak için kullanacağımız tipler Microsoft.CodeAnalysis.CSharp.Scripting namespace'i içerisinde bulunuyor.

İlk olarak en basit olandan başlıyoruz. CSharpScript.EvaluateScript metodu bizim basit C# ifadelerini çalıştırıp sonuçlarını almamızı sağlayan metot.

class Program
{
    static void Main(string[] args)
    {
        RunAsync().Wait();
    }

    static async Task RunAsync()
    {
        var result = await CSharpScript.EvaluateAsync("1+1");
        var result2 = await CSharpScript.EvaluateAsync<int>("1+1");
        Console.WriteLine($"result:{result}, result2:{result2}");
    }
}

Eğer EvaluateAsync'in generic olmayan metodunu kullanırsak bize sonuç object tipinden dönüyor. Ancak generic metodu kullanırsak strongly-typed olarak script'in sonucunu alabiliyoruz.

class Program
{
    static void Main(string[] args)
    {
        RunAsync().Wait();
    }

    static async Task RunAsync()
    {
        var result = await CSharpScript.EvaluateAsync<int>("int x=10;int y=12; int z=x+y; z");
        Console.WriteLine($"result:{result}");
    }
}

Yukarıda yazdığımız koda tekrar bakmamızda fayda var. "int x=10;int y=12; int z=x+y; z" aslında derlenebilir bir C# kodu değil. Ancak scripting API'larında bir değişkenin o anki değerini alabilmek için doğrudan adını yazdığımızda değerini alabiliyoruz. Aynı diğer scripting ortamlarında olduğu gibi.

EvaluateAsync metodu opsiyonel ikinci parametre olarak bizden ScriptOptions tipinde bir object bekliyor. Bu parametre ile istediğimiz namespace'i veya kütüphaneyi referans olarak ekleyebiliyoruz. Böylece EvaluateAsync içerisinde çalıştıracağımız kodlarda eklediğimiz kütüphanelerden ve namespacelerden tipleri kullanabiliyoruz. Eğer bu namespaceleri veya kütüphaneleri eklemezsek runtimeda scriptin derlenmesi esnasında compilation error alırız.

Örneğin C# 6.0 ile beraber static tiplerin isimlerini using ile eklediğimizde kod içerisinde artık doğrudan tipin ismini kullanmadan metodun adıyla çağrım yapabiliyorduk. Math sınıfı içerisindeki Tan metodunu çağırdığımız aşağıdaki kodu düşünelim.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    try
    {
        var result = await CSharpScript.EvaluateAsync<int>("Tan(20);");
        Console.WriteLine($"result:{result}");
    }
    catch (CompilationErrorException ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

Bu kodu çalıştırdığımızda compilation error alırız. Çünkü using ifadesi ile Math tipini script içerisinde referans almadık.

Eğer aşağıdaki gibi System.Math namespace'ini script içerisine referans olarak eklersek Tan(20) kodu başarılı olarak çalışacak ve sonucunu alabileceğiz.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    try
    {
        var result = await CSharpScript.EvaluateAsync<double>("Tan(90);"ScriptOptions.Default.WithImports("System.Math"));
        Console.WriteLine($"result:{result}");
    }
    catch (CompilationErrorException ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

Şimdiye kadar yaptığımız örneklerden de gördüğünüz üzere EvaluateAsync metodu context bağımsız olarak çalışıyor. Yani bir kod veriyorsunuz, derleyip, kodu çalıştırıyor ancak sonrasında içerisindeki tüm değişkenler ve değerleri kaybolup gidiyor. Peki ya aynı interactive window senaryosunda olduğu gibi çalıştıracağımız kodu dışarıdan alıyorsak ve bu kodu da çalıştırdığımız contexti korumak istiyorsak ne yapacağız ? İşte tam burada devreye EvaluateAsync metodunun biraz daha gelişmiş versiyonu olan RunAsync metodu devreye giriyor.

RunAsync metodu EvaluateAsync metodunun aksine bize ScriptState tipinde bir object döndürüyor. Bu object de kodu çalıştırdığımız contexti içerisinde barındırıyor.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    var state = await CSharpScript.RunAsync<int>("1+2");
}

ScriptState içerisindeki property ve metotlara kısaca bakarsak.

  • ContinueWithAsync metotları tahmin edeceğiniz üzere mevcut context üzerinden yeni kodlar çalıştırmamızı sağlar.
  • GetVariable metodu script içerisinde o anda tanımlı olan belirli bir değişkenle ilgili bilgileri alabilmemizi sağlar.
  • ReturnValue ise çalıştırdığımız kodun geri dönüş değerini içerir. EvaluteAsync metodundan doğrudan dönen değer burada ReturnValue propertysinde bulunuyor.
  • Script propertysi son çalıştırdığımız script ile ilgili bilgileri saklar.
  • Variables propertysi ise script içerisinde o anda tanımlı olan tüm değişkenlerler ile ilgili bilgileri içerisinde barındırır.

Şimdi ContinueWithAsync ile ufak bir örnek yapalım.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    var state = await CSharpScript.RunAsync<int>("1+2");
    Console.WriteLine(state.ReturnValue);
    var state2 = await state.ContinueWithAsync("int i=1;");
    var state3 = await state2.ContinueWithAsync<int>("i+5");
    Console.WriteLine(state3.ReturnValue);
}

Yukarıda görüldüğü gibi öncelikle basit bir toplama işlemi çalıştırdık. Sonrasında aynı context içerisinden devam edip bir değişken tanımladık. Bir sonraki adımda ise bu değişkeni kullanarak bir toplama işlemi daha yaptık. Burada en çok dikkat çekmek istediğim nokta buradaki işlemlerden dönen tiplerin immutable olması. Yani her yeni script çalıştırışımızda bize yeni bir ScriptState nesnesi geliyor. Aslında baktığımızda bu state nesnelerini uygun bir şekilde saklarsak ihtiyacımıza göre ilgili kodları hiç çalıştırmamış gibi bir önceki state üzerinden devam etme imkanına da sahip olabiliriz.

Yukarıdaki kodun çıktısını aşağıda görebilirsiniz.

Yukarıda ScriptState tipi içerisinde script içerisinde tanımladığımız değişkenlerle ilgili bilgileri içerisinde saklar demiştik. Şimdi bununla ilgili de ufak bir örnek yapalım.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    var state = await CSharpScript.RunAsync("int x=1;");
    PrintVariables(state);
    var state2 = await state.ContinueWithAsync("x=4;");
    PrintVariables(state2);
    var state3 = await state2.ContinueWithAsync("x=10;");
    PrintVariables(state3);
}

private static void PrintVariables(ScriptState state)
{
    foreach (var variable in state.Variables)
    {
        Console.WriteLine($"Variable Name: {variable.Name},Type: {variable.Type.Name}, Value: {variable.Value}");
    }
}

ScriptState nesnesi o anda script içerisinde tanımlı olan değişkenlerle ilgili isim,tip ve o anki değeri gibi bilgileri içerisinde barındırıyor. Dolayısıyla bizde bu nesne üzerinden değişkenlerle ilgili bilgilere ulaşabiliyoruz.

Yukarıdaki kodun çıktısına bakarsak.

Yukarıdaki çıktıyla beraber kodu beraber incelersek her bir state nesnesi içerisinde değişkenin değerinin değiştiğini görüyoruz.

CSharpScript tipi içerisinde son olarak Create statik metodunu kullanarak da script çalıştırabiliyoruz. Ancak bu metot diğerlerinden biraz farklı. Öncelikle bu metodu çağırdığımızda parametre olarak verdiğimiz kod anında çalıştırılmıyor. Çalıştırma operasyonunu scripti yarattıktan sonra bizim tetiklememiz gerekiyor.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    var script = CSharpScript.Create("1+2");
    var state = await script.RunAsync();
}

Ayrıca burada diğer metotlardan farklı olarak script olarak verdiğimiz kodun derlenmesi RunAsync metodunu ilk çağırışımızda yapılıyor. Eğer istersek biz de Compile metodunu kullanarak derleme işlemini önceden tetikleyebiliyoruz.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    var script = CSharpScript.Create("1+2");
    script.Compile();
    var state = await script.RunAsync();
}

Script tipi üzerinden script çalıştırdığımızda bu tip içerisinde kodu derlemek için gerekli olan tüm yapılar(syntax tree vs...) saklanıyor. Bu nedenle eğer hep aynı kodu çalıştıracaksak bu yapılar bizim için ekstra yük demek. Bunun için CreateDelegate metodunu kullanarak içerisinde bu ekstra yapıları içermeyen daha basit bir tip elde edebiliriz ve bu tip üzerinde kodu daha hızlı ve efektif şekilde çalıştırabiliriz.

static void Main(string[] args)
{
    RunAsync().Wait();
}

static async Task RunAsync()
{
    var script = CSharpScript.Create("1+2");
    var runner = script.CreateDelegate();
    var result = await runner();
    Console.WriteLine(result);
}

Yukarıdaki kodu bilgisayarınızda çalıştırırsanız delegate yaratma aşamasının biraz vakit aldığını ancak sonrasında delegate'i çalıştırma işleminin çok hızlı olduğunu göreceksiniz.

Roslyn içerisinde scripting API'larının kullanımları bu şekilde. Gördüğünüz gibi API'ların hepsi oldukça kuvvetli ve çok farklı senaryolara da cevap verebilecek şekilde tasarlanmış. Bu API'lar kullanılarak Interactive Window gibi daha pek çok farklı uygulama da yapılabilir. Örneğin web sayfası üzerinden aldığınız kodları serverda çalıştırıp sonuçlarını yine web sayfası üzerinde gösterebilirsiniz. Böylece kullanıcılar için ufak bir playground yapmış olabilirsiniz.

Roslyn'in Scripting API'ları da aynı compilerlar gibi open source. Eğer bakmak isterseniz buradan ulaşabilirsiniz. Aynı şekilde Interactive Window Scripting API'ları kullanılarak nasıl yazılmış merak ediyorsanız Github üzerinden kodlarına ulaşabilirsiniz.

Bir sonraki yazıda görüşmek üzere



C# Interactive Window

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

C# Interactive Window ile ilgili ilk yazımı bundan yaklaşık 3 sene önce yazmışım. Roslyn projesi ilk duyurulduğunda projenin gösterilen en önemli kısımlarından biri Interactive Window'du. Ancak zaman geçtikçe öncelikler değişti ve interactive window'un arka planda kullandığı scripting API'larının çıkışı RTM sonrasına ertelendi ve dolayısıyla interactive window'a da ancak Visual Studio 2015 Update 1 ile kavuşabildik.

Interactive Window Nedir ?

Interactive window, C# dili ile çalışan ve zengin editör desteğine sahip bir read-eval-print-loop(REPL). Read-eval-print-loop terimini biraz daha açarsak, yazmış olduğunuz C# kodunu okuyan ve bunu arka planda çalıştırdıktan sonra da sonucunu ekrana yazan bir uygulama. Yani artık bir kodu denemek için en basitinden bir console uygulaması yaratmaya gerek kalmadan doğrudan kodu REPL uygulaması içerisinden çalıştırıp hızlı bir şekilde sonucunu görebiliriz. Bunun yanında yeni bir dil yeniliği geldiğinde de yine bu yeniliği hızlı bir şekilde REPL uygulaması içerisinde test etmemiz de mümkün.

Visual Studio 2015 Update 1'i bilgisayarımıza kurduktan sonra C# Interactive Window'u 2 şekilde açabiliriz. Bunların ilki ve en kolayı Visual Studio'nun sağ üst köşesinde bulunan Quick Launch.

Diğer seçenek ise View => Other Windows => C# Interactive üst menüsünü kullanarak açmak.

Interactive window ilk açıldığında ise aşağıdaki gibi görünüyor.

Interactive Window'un bir REPL(read-eval-print-loop) olduğundan bahsetmiştik. Dolayısıyla ilk olarak bir Hello World yazıp sonucu görmekte fayda var :)

> Console.WriteLine("Hello Interactive Window"); 
Hello Interactive Window

Gördüğümüz gibi Hello Interactive Window yazısı çalıştırdığımız kodun çıktısı olarak ekrana yazıldı. O zaman işleri biraz daha karıştıralım ve önce bir değişken tanımlayalım ve sonrasında da bu değişken üzerinden bir işlem yapalım.

> List<int> numbers = new List<int> { 4, 1, 6, 3, 9 }; 
> numbers.OrderBy(t => t).ToList().ForEach(t => Console.WriteLine(t));
1
3
4
6
9

Interactive Window içerisinde yazacağımız kodların illa tek satırdan oluşması gibi kısıt yok. Aynı kod yazar gibi Enter tuşuna basıp kod yazmaya devam edebiliriz.

> foreach(var item in numbers.OrderBy(t=>t)) 
.{
. Console.WriteLine(item);
.}
1
3
4
6
9

Interactive window içerisinde tanımladığımız değişkenler bir context içerisinde saklanıyor. Dolayısıyla önceki kod parçalarında tanımladığımız değişkenlere istediğiniz zaman window içerisinden tekrar ulaşıp kullanabiliyoruz.

Interactive Window içerisinde metotlar yazıp sonrasında bu metotları çağırmamız da mümkün.

> void PrintOrderedNumbers(List<int> unorderedList) 
.{
. unorderedList.OrderBy(t => t).ToList().ForEach(t => Console.WriteLine(t));
.}
> PrintOrderedNumbers(numbers);
1
3
4
6
9

Interactive window içerisinde kullanmak istediğimiz bir tipin bulunduğu namespace'i using ifadesi kullanarak ekleyebilmekteyiz.

> using System.Threading; 

Interactive Window içerisindeki context default olarak async tanımlı. Dolayısıyla await kullanarak istediğimiz bir async bir metodu çağırabiliriz.

> using System.Web; 
> using System.Net;
> WebClient client = new WebClient();
> var response = await client.DownloadStringTaskAsync("http://ilkayilknur.com");
> Console.WriteLine(response.Substring(0, 50));
<!DOCTYPE html> <html>
<head prefix="fb: http://

Directives

Interactive Window içerisinde bazı özel komutları kullanarak özel bazı işlemler yapmamız da mümkün. Bunlardan ilki Interactive Window içerisine dll referansı ekleme komutu'i olan #r komutu.

Referansı ekledikten sonra yukarıda görüldüğü gibi dll içerisindeki tipleri intellisense'te görebiliyoruz ve yazacağımız kodlarda bu tipleri kullanabiliyoruz.

Eğer interactive window ekranındaki kodları temizlemek istersek #cls veya #clear komutlarını kullanabiliriz. Bu komutlar sadece ekranda bulunan kodları temizliyor. Yani daha önceden tanımlamış olduğumuz değişken veya metotların hepsini koruyor. Eğer interactive window'u tamamen sıfırlamak yani tüm tanımladığınız değişkenler,metotlar vb.. tümünden kurtulmak istersek kullanacağımız komut #reset komutu olacak.

Interactive window içerisinde dışarıdan bir dosya içerisinde bulunan kodları çalıştırmamız da mümkün. Örneğin aşağıdaki kodu bir txt dosyasına kopyalayıp bilgisayarda bu dosyayı kaydedelim.

void PrintOrderedNumbers(List<int> unorderedList) 
{
unorderedList.OrderBy(t => t).ToList().ForEach(t => Console.WriteLine(t));
}
PrintOrderedNumbers(numbers);

Sonrasında interactive window içerisinde #load komutunu kullanarak bu dosya içerisindeki kodları çalıştırıp sonucunu interactive window içerisinde görebiliriz.

> #load "C:\Users\ilkay\Documents\GitHub\xomnicloud\xomni-sdk-dotnet\src\XOMNI.SDK.Public\bin\Debug\code.txt"
1
3
4
6
9

Son olarak ise interactive window içerisinde komutlarla ilgili yardım almak istersek #help komutunu kullanabiliyoruz.

Görüldüğü gibi interactive window Visual Studio içerisindeki en vazgeçilmez özelliklerden biri olmaya aday. Özellikle ufak bir kod parçasının nasıl çalıştığını görmek için veya hızlıca demolar yapmak için oldukça güzel bir ortam. Hala daha bazı eksikleri olsa da (örneğin nugetten referans ekleme) ileride bu eksik noktalar da giderilecektir diye düşünüyorum.

Bir sonraki yazıda görüşmek üzere.



C# 6.0 String Interpolation

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

C# 6.0'ın en önde gelen teması bizim kod yazmamızı kolaylaştırmak ve mümkün olduğu kadar az hata yapmamızı sağlamak. nameof operatorü, ?. null propogation operatorü gibi yenilikleri hep bu belirlenen temanın birer ürünü olarak düşünebiliriz.

C# 6.0 içerisinde bizim kod yazmamızı kolaylaştıran en önemli yeniliklerden biri de string interpolation özelliği. String interpolationla beraber string içerisinde belirli yerlere istediğimiz değerleri çok daha kolay ve hata yapma olasılığımız daha az olacak şekilde yazabiliyoruz.

Örneğin aşağıdaki gibi bir kod olduğunu düşünelim.

class Program
{
    static void Main(string[] args)
    {
        int id = 12;
        string name = "Mahmut";
        string summary = string.Format("Musteri adi:{0},Musteri Id:{1}", name, id);
    }
}

C# 6.0 öncesinde yukarıda gördüğümüz şekilde bir string içerisindeki belirli alanlara string.format metodunu kullanarak istediğimiz değerleri basabiliyorduk. Buradaki en önemli sıkıntılardan biri değer basacağımız alanları numara ile belirlememiz. Yani eğer ileride bu string üzerinde bir değişiklik yapmamız gerekirse manuel bir şekilde string içerisine yeni bir alan ekleyeceğiz. Belki bundan sonra bazı alanları da string içerisinden kaldıracağız. Tabi insanlık hali bunları yaparken hata yapma olasılığımız da var. Tüm bu işlemler sonucunda belki aşağıdaki gibi hatalı bir kod yazma olasılığımız da yüksek.

class Program
{
    static void Main(string[] args)
    {
        int id = 12;
        string name = "Mahmut";
        string surname = "Gates";
        string summary = string.Format("Musteri adi:{0},Musteri Soyadı:{2}", name, surname);
    }
}

Sanıyorum ki çoğunuz hatayı zaten hemen farketmişsinizdir :) Ancak böyle bir durumla karşılaştığımızda bu hatayı maalesef derleme zamanında yakalamamız imkansız. İşte string interpolation bizim bu hatalara düşmemizi bir nebze olsun azaltıyor. Peki gelelim string interpolation'ı nasıl kullanacağımıza.

Öncelikle string interpolation özelliğini kullanacağımız string'in başına $ işareti koymamız gerekiyor. $ işareti koyduğumuzu anlayan compiler ve IDE yazdığımız string içerisinde bize gerekli olacak olan intellisense'i de sağlıyor.

String interpolationda daha önce string format içerisinde numara ile sıraladığımız alanlara artık doğrudan yazacağımız değerin kendisini yazıyoruz. Yani aşağıdaki 2 kullanım da aslında aynı çıktıyı veriyor.

string name = "Mahmut";
string surname = "Gates";
string summary = string.Format("Musteri adi:{0},Musteri Soyadı:{1}", name, surname);
string summary2 = $"Musteri adi:{name},Musteri Soyadı:{surname}";

Aynı zamanda çeşitli formatlamaları da aynı string.format içerisinde kullandığımız gibi string interpolation içerisinde de kullanmamız mümkün.

class Program
{
    static void Main(string[] args)
    {
        double d = 10.3123113;
        string s = $"Value is {d:00.00}";
    }
}

Arka Planda Neler Oluyor ?

String interpolation özelliği aslında derleme zamanı çalışan bir özellik. Yani kodunuzun derlenmesi sırasında compiler sizin string interpolation kullandığınız yeri algılayıp oradaki kodu string.formatlı versiyona çeviriyor. Örnek olarak yukarıda yazdığımız kodu derleyip ILSpy ile açarsak aşağıdaki gibi bir kodla karşılaşıyoruz.

namespace ConsoleApplication2
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            string arg = "Mahmut";
            string arg2 = "Gates";
            string text = string.Format("Musteri adi:{0},Musteri Soyadı:{1}", arg, arg2);
        }
    }
}

Gördüğünüz gibi derleme zamanında string interpolation kullandığımız bölüm compiler tarafından değiştirilerek string.formatlı hale çevrildi.

string.format vs string interpolation

String interpolationı şu ana kadar hep string.format ile karşılaştırdık. Peki string.format kullanımını tamamen bırakıyor muyuz diye aklınıza bir soru gelebilir. String.Format'ın en önemli kullanım alanlarından biri de localization senaryoları. string interpolation içerisinde şu anda localization mekanizmasını sağlayacak bir yapı bulunmuyor. Yani eğer localize içeriklerinizi C# dosyası dışında bir yerde(resource file vs..) saklıyorsanız string interpolation özelliğini kullanmanız şu an için mümkün değil. Burada yine string.format ile ilerlemek gerekiyor.

String interpolationı kullanırken dikkat etmemiz gereken notalardan biri de string interpolationın Culture olarak CurrentCulture'ı kullanması. Eğer Invariant Culture kullanmak isterseniz küçük bir helper metot yazıp ilerleyebilirsiniz.

class Program
{
    static void Main(string[] args)
    {
        string name = "Mahmut";
        string surname = "Gates";
        string summary2 = ToInvariant($"Musteri adi:{name},Musteri Soyadı:{surname}");
    }

    static string ToInvariant(FormattableString str)
    {
        return str.ToString(CultureInfo.InvariantCulture);
    }
}

Yukarıdaki koddan da anlayabileceğiniz üzere stringi interpolation kullanarak yarattığımız herhangi bir string FormattableString'e implicit olarak çevirebiliyoruz. FormattableString sınıfı içerisinde ise string interpolation kullanarak yarattığımız stringle ilgili çeşitli bilgiler yer alıyor. Bunlar string interpolation kullanarak yazığımız ifadenin string.format karşılığı ve string içerisinde belirli alanlara yerleştirdiğimiz değerler. C# Interactive Window içerisinde aşağıdaki gibi FormattableString içerisindeki değerleri görebilirsiniz.

Gördüğünüz gibi string interpolation belirli çerçevelerde de olsa bizim string yaratma işlemlerimizi bir nebze kolaylaştırıyor.

Bir sonraki yazıda görüşmek üzere.



Açık Akademi Yaz Okulu - C# ve LINQ Oturumu

Açık Akademi Yaz Okulunun bizim için ikinci günü LINQ, C# ve Web API günüydü. Sabahtan aslında LINQ anlatmam gerekirken yine dayanamayıp C#'ın geçmişinden, versiyonlardan ve LINQ dışındaki çeşitli özelliklerden de bahsettim. Gökhan da sonrasında Web API anlattı ve günü tamamladık.

Sunumda yaptığım demolara buradan erişebilirsiniz.

İki gün benim için oldukça keyifli geçti. Umarım dinleyenler için de faydalı olmuştur.