İlkay İlknur

just a developer...

Visual Studio 2015 Update 2 İle Gelen Yenilikler

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Build 2016'nın en önemli duyurularından biri de Visual Studio 2015 Update 2'nin release olmasıydı. Update 2 içerisinden bolca bug fix barındırsada bahsetmeye değer bazı yeni özellikler de barındırmakta.

Universal Platform Yenilikleri

Update 2 ile beraber Universal App'lerde kullandığımız Microsoft.NETCore.UniversalWindowsPlatform nuget paketininde 5.1.0 versiyonu release oldu. Visual Studio 2015 Update 2'yi yüklediğinizde bu nuget paketini update etmenizde fayda var.

Update 2 ile beraber gelen bir diğer özellik ise Universal App yaratma aşamasında karşımıza çıkan version seçim ekranı. Bu ekran ile uygulamanızın target edeceği ve minimum olarak destekleyeceği Windows 10 versiyonunu uygulama yaratırken seçebiliyorsunuz.

Update 2 ile beraber gelen en beğendiğim özellik ise basit ama zaman kazandıran bir özellik. Daha önceden Universal App'inizi store'a göndermek için paket yaratmak istediğinizde her seferinde live accountunuzla login olmak zorunda kalıyordunuz. Ancak Update 2 ile beraber bu sorunu çözmüşler ve Store'a bir kere login olduğunuzda Visual Studio artık bu account bilgilerini otomatik olarak hatırlıyor.

Interactive Window Yenilikleri

Visual Studio 2015 Update 1 ile beraber gelen en önemli yeniliklerden biri de Interactive Window'du. (Eğer daha önce Interactive Window'u duymadıysanız yazmış olduğum yazıyı okuyabilirsiniz.) Update 2 ile beraber Interactive Window tarafında da yenilikler mevcut. Bu yenilikler çalışmış olduğunuz proje içerisindeki kodları hızlı bir şekilde Interactive Window üzerinden çalıştırmanıza olanak sağlıyor. Bunun için Visual Studio içerisinde çalıştırmak istediğiniz kodu seçip sağ tıklayıp "Execute in Interactive"'i tıklamanız yeterli.

Editör Yenilikleri

Update 2 içerisinde güzel editör yenilikleri de bulunmakta. Bunlardan ilki using/import eklerken artık fuzzy matching yapılması. Yani eğer bir tipin adını yanlış yazarsanız Visual Studio tipin adından tahminde bulunuyor ve size uygun öneriyi sunup hem tipin adını düzeltiyor hem de ilgili using/import'u ekliyor.

Update 2 içerisinde ayrıca yeni refactoringler de bulunuyor. Bunlardan ilki delegate işletimlerinde null propagator operatörü kullanımını öneren refactoring.

Diğer refactoring ise make method synchronous refactoringi.

Bu yazıda değinmek istediğim yenilikler bunlar. Update 2 ile beraber gelen tüm yenilikleri https://www.visualstudio.com/en-us/news/vs2015-update2-vs.aspx adresinde bulabilirsiniz.



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...



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...



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.



Visual Studio 2015 Sürümleri ve Kurulum Yenilikleri

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Zaman hızla akıp geçiyor valla :) Bundan 1.5 yıl önce Visual Studio 14 kod ismiyle ilk CTP'si yayınlanan Visual Studio'nun yeni versiyonu, Visual Studio 2015 ismiyle geçtiğimiz günlerde RTM(Release to Manufacturing) oldu. Yani bunun anlamı, artık rahat rahat development yaptığımız bilgisayarlarımıza kurabiliriz ve productionda kullanabiliriz.

Kurulum festivaline başlamadan önce isterseniz Visual Studio 2015'in sürümlerine bir göz atalım ve kurulum esnasında karşımıza ne gibi yenilikler çıkıyor kısaca bakalım.

Visual Studio 2015 Sürümleri

Kuruluma başlamadan önce en kritik soru tabiki de "Hangi sürümü indirip kurmalıyım ?" sorusu. Visual Studio 2015 ile beraber sürüm isimlerinde de bazı değişiklikler var. Visual Studio 2013'de Community,Professional,Premium ve Ultimate sürümleri bulunurken Visual Studio 2015'in Community,Professional ve Enterprise sürümleri bulunmakta. Toparlayacak olursak Community ve Professinal sürümleri aynı şekilde devam ediyor ancak Visual Studio 2013'deki Premium ve Ultimate sürümleri Enterprise sürümü adı altında birleştirildi. Community sürümü Visual Studio 2015'de de ücretsiz. Professional ve Ultimate için lisans almanız veya MSDN üyeliğinizin olması gerekiyor. Ürün fiyatları için şuradaki linke bakabilirsiniz.

Peki Community,Professional ve Enterprise sürümleri arasında ne gibi farklar var diyorsanız buradaki link size yardımcı olacaktır.

Kurulumda Ne Gibi Yenilikler Var ?

Yukarıdaki bilgiler ışığında bilgisayarımıza kuracağımız Visual Studio 2015 sürümünü seçtik ve artık kuruluma hazırız.

Visual Studio'nun kurulumu aslında her zaman basit olmuştur. Install'a tıkla sonra next, next, next :) Ancak en büyük problemlerden biri de kurulumda aslında hiç işimize yaramayacak olan componentlerinde bilgisayarımıza yüklenmesi ve bunu önleyemememizdi. Hatta Uservoice'te en çok oy alan isteklerden biriydi bu. Microsoft'da Visual Studio 2015'de bu isteği göz ardı etmemiş ve kurulum sırasında artık bize daha uzun bir component listesi çıkarıyor ve biz arasından aslında hiç ihtiyacımız olmayacak olan componentleri kurmadan geçebiliyoruz. Tabi bunu yapmak için kurulum sırasında Custom kurulumu seçmemiz gerekiyor. Typical'ı seçersek web ve masaüstü uygulamaları geliştirmek için gerekli olan componentler otomatik olarak yükleniyor.

Custom kurulumu seçtikten sonra karşımıza yukarıdaki gibi bir liste geliyor. Burada dikkatimizi çekmesi gereken bazı seçenekler var :)

  • Xamarin
  • Apache Cordova
  • Microsoft Visual Studio Emulator for Android
  • Git for Windows
  • Github Extesion for Visual Studio

Bunlar Visual Studio 2015 ile beraber kurulumda ilk kez karşılaştığımız componentler. Daha önce bunların hepsini ayrı ayrı extension vs.. olarak kurmamız gerekirken artık Visual Studio 2015 kurulumu ile beraber bilgisayarımıza tek bir adımda yükleyebiliyoruz. Android developmentı için gerekli olan Java kurulumu da yine bu kurulum içerisinde gerçekleştiriliyor.

Visual Studio 2015 kurulum aşaması bu kadar. Bir sonraki adım için yeni yazıda görüşmek üzere :)



Visual Studio 2015 Preview İçerisinde C# 6.0

Bu videomuzda Visual Studio 2015 Preview içerisindeki C# 6.0 özelliklerine bakıyoruz.

Video içerisindeki örneklere Github'dan erişebilirsiniz.



Microsoft Connect Etkinliğinden Notlar

Geçtiğimiz haftalarda düzenlenen Microsoft Connect etkiliğinde duyurulan yeniliklerle ilgili kısa bir video çektim.

Video içerisinde değindiğim konulara ait linkler

Umarım faydalı olur.