İlkay İlknur

just a developer...

C# 7.2 - Value Typelarda Referans Semantiği Yenilikleri

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Visual Studio 15.5 update'inin release olması ile beraber C#'ın bir sonraki minor release'i olan 7.2 versiyonu da artık RTM oldu. Daha önceki C# 7.1 yazımda da bahsettiğim üzere minor C# versiyonları Visual Studio içerisinde default olarak aktif olmuyor ve bu özellikleri kullanabilmemiz için ufak bir ayar yapmamız gerekiyor. Bu gerekli olan ayara da C# 7.1 Yenilikleri yazımdan ulaşabilirsiniz.

C# 7.2'de de yine C# 7.1'de olduğu gibi ufak ve faydalı yenilikler var. Ancak C# 7.2 sadece ufak yeniliklerin olduğu bir release değil. C# 7.2'nin ana teması, value type'larla çalışırken onları pass-by-reference mantığı ile kullanarak value typeların sahip olduğu kopyalanma özelliklerinin önüne geçip allocationı ve kopyalanma operasyonlarını azaltmak. Bu yazımızın konusu da bu tema kapsamında gelen yenilikler. C# 7.2 ile beraber gelen diğer yeniliklere de başka bir yazıda göz atacağız.

Bu Özellikler Neden Gerekliydi ?

Value typelar, özellikle de structlar performans kritik algoritmalarda, oyunlarda, 3D modelleme vs.. gibi alanlarda oldukça fazla kullanılmakta. Bunun en önemli nedeni value typeların heap allocationa neden olmaması nedeniyle Garbage Collector'ın getirebileceği tahmin edilemeyen yüklerden ve sorunlardan olabildiğince kaçınmak. Ancak value typelar bir metoda parametre olarak geçildiklerinde eğer herhangi bir ref parametre kullanılmazsa value typeların bir kopyası yaratılıp geçilir (pass-by-value) . Örneğin, .NET Framework içerisindeki System.Windows.Media.Media3D.Matrix3D structı içerisinde 16 tane double property bulunmakta. Bu da toplamda 128 byte ediyor. Dolayısıyla siz bu structı metotlara parametre olarak geçmeye kalkarsanız bu 128 bytelık struct sürekli olarak kopyalanarak metotlara geçilecektir. Elinizde bu structlardan oldukça fazla olduğunu düşünürseniz, bir metot çağırımı bile oldukça sıkıntılı sonuçlara yol açabilir. Bundan kaçınmak için tabi ki de C# içerisinde bazı çözümler var. Ancak C# 7.2 bu özelliklere ekstra yenilikler ekleyerek özellikle structlarla çalışmayı daha kolay ve özellikle güvenilir hale getiriyor. Dolayısıyla aşağıda anlatmaya çalışacağım yenilikleri bu konseptte değerlendirmekte fayda var.

in Parametreleri

Şu ana kadar C# içerisinde bir value type'ı bir metoda referansıyla parametre olarak geçmek istediğimizde out ve ref parametrelerini kullanabiliyorduk. Böylece value typeların metot çağırılırken kopyalanmasının önüne geçebiliyoruz ve referansıyla gönderebiliyoruz. Bu seçeneklerden, out parametreyi kullandığımızda, out parametrede çağırılan metot bu değişkene mutlaka bir değer ataması yapması gerekirken, ref parametrelerde ise değişken yine referansı ile metoda gelirken metodun değişken üzerinde bir değişiklik yapması zorunlu değil.

static void Out(out int x)
{
    x = 12;
}

static void Ref(ref int x)
{
    //Bazı durumlarda değiştirilebilir.
    if (x > 10)
    {
        x = 9;
    }
}

C# 7.2 ile beraber gelen in parametreleri ise yine değişkenin referansıyla metoda gönderilmesini sağlarken çağrılan metodun bu değişkeni değiştiremeyeceğinden emin olunmasını sağlıyor. Böylece çağırılan metot in parametreyi değiştiremeyeceği için gönderdiğiniz value type'ın özellikle de struct'ın değişmediğinden emin olabilirsiniz.

Örneğin,

static void In(in int x)
{
    x = 12;
}

Yukarıdaki gibi gelen bir in parametreye bir değer ataması yapmak isterseniz derleme hatası alıyorsunuz.

in parametre kabul eden bir metodu çağırmak istediğimizde iki şekilde çağırma yapabilmemiz mümkün. Birincisi out parametrelerde olduğu gibi in parametrenin başına in keywordünü eklemek.

static void Main(string[] args)
{
    int k = 1;
    In(in k);
}

Diğeri ise in keywordünü eklemeden çağırmak. Eğer in parametre yolladığınızı kodu okuyan kişinin bilmesini istiyorsanız parametrenin başına in yazmanız faydalı olabilir. Ama kullanım şekli tamamen size kalmış.

static void Main(string[] args)
{
    int k = 1;

    In(in k);            
    In(k);
}

in parametrelerin en büyük avantajı value typelar ile elde ediliyor.Reference typelarda etkisinin pek olmadığını belirtmemizde fayda var.

ref readonly returns

in parametrelerle, parametre referansıyla ve değiştirelemez bir şekilde metoda parametre geçilirken bu özellikle de dönüş değeri olan value type referansıyla döndürülür ve bu referans üzerinden döndürülen value type değiştirilemez. Bu özelliğin faydalı olabileceği kullanım alanlarında birini kısaca anlatmaya çalışalım.

Örneğin Point isimli bir struct olduğunu düşünelim.

struct Point
{
    public int X { getset; }
    public int Y { getset; }
}

Bunun için Default değerini kapsayacak bir property koymak istersek şu şekilde bir ekleme yapmamız gerekir.

struct Point
{
    public int X { getset; }
    public int Y { getset; }
    public static Point Default => new Point();
}

Burada her Default propertysi kullanıldığında stackde yeni bir Point yaratılır. Halbuki bunun yerine ref readonly olarak döndürürsek tek bir Point yaratıp sürekli olarak bunun referansını döndürebiliriz.

struct Point
{
    public int X { getset; }
    public int Y { getset; }
    private static Point defaultp = new Point();
    public static ref readonly Point Default => ref defaultp;
}

Bu şekilde Point structını tanımladıktan sonra Point üzerinden Default propertysine aşağıdaki gibi ulaşabiliriz.

static void Main(string[] args)
{
    ref readonly var defaultp = ref Point.Default;
}

Bu şekilde bir kullanımda defaultp değişkeni içerisinde readonly referans bulunduğu için Main metot üzerinde defaultp değişkeni üzerinden bir değer ataması yapılması mümkün olmayacaktır ve compiler kodu derlemeyecektir.

static void Main(string[] args)
{
    ref readonly var defaultp = ref Point.Default;
    //ref readonly !!!
    defaultp.X = 1; //---> Mümkün değil !!!
}

ref readonly olarak dönen bir değerin kopyasını almak istersek de dönen değeri ref readonly olmayan bir değişkene atamasını yapmamız yeterli.

static void Main(string[] args)
{
    var defaultp = Point.Default;
    //Default'in yeni bir kopyası oluşturuldu. 
    defaultp.X = 1; //---> Artık mümkün :)
}

Bu özelliği isterseniz metotların dönüş değerleri için de kullanabilirsiniz. Biz örnek olarak property yaptık ancak bu özellik metotların dönüş değerleri için de kullanılabilir.

readonly Structs

C# 7.2 öncesinde readonly olarak tanımlanan bir struct variable'ı üzerinde struct içerisindeki bir instance metodu çağırmak istediğimizde derleyeceği o metodun structı değiştirip değiştirmeyeceğini bilemediği için otomatik olarak structı arka planda geçici bir değişkene atayıp o değişken üzerinden ilgili metodu çalıştırıyordu. Bunun da performans olarak bazı sıkıntıları olabiliyordu. Örnek senaryo olarak https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/ bu yazıyı okuyabilirsiniz. Bu performans sorunları nedeniyle de çoğu zaman readonly kullanmaktan vazgeçilebiliyordu.

C# 7.2 ile beraber struct tanımlamasının başına readonly yazarak structların readonly olmasını sağlayabiliyoruz. Böylece derleyici de yukarıda belirttiğim senaryoda geçici bir değişken yaratmak durumunda kalmıyor ve performans sıkıntılarının da önüne geçilmiş olunuyor.

readonly olarak tanımladığımız structların içindeki değerlere atamalar sadece constructor içerisinde yapılabiliyor. Bunun haricinde başka bir yerde atama yapmak mümkün değil.

readonly struct Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }       
}

Şimdilik bu tema kapsamında bu yazıda bahsedeceklerimiz bu kadar. C# 7.2 ile beraber gelen ve yine tema kapsamında olan Span< T>'nin kullanımından ise başka bir yazıda bahsediyor olacağım. Bu yeniliklerin özellikle yüksek performanslı sistemlerin, oyunların optimizasyonu amacıyla yapıldığını hatırlatmakta fayda var. Biz belki kod yazarken sürekli structları veya bu yenilikleri kullanmıyor olabiliriz ancak kullandığımız frameworkler, toollar bu tipleri arka planda kullanıyorlar. Dolayısıyla bu yenilikler doğrudan olmasa bile dolaylı yoldan bizleri etkiliyor olacak. Mesela buradaki pull request içerisinde corefx içerisinde bu değişikliklerin adapte edildiğini görebilirsiniz.

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



C# 7.1 Yenilikleri

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Daha önceki blog yazılarımda ve videolarımda C#'ın minor releaselerinin çıkarılması için çalışmalar yapıldığından bahsetmiştim. Şimdiye kadar baktığımızda her yeni Visual Studio versiyonu ile beraber C#'ın da yeni versiyonu çıkıyordu. Bu nedenle hem büyük kapsamlı yenilikler hem de ufak yenilikler doğrudan tek bir versiyon içerisinde bulunuyordu. Halbuki dil içerisindeki bazı yenilikler geliştirilmesi bitse bile yeni versiyon çıkana kadar biz developerlarla buluşamıyordu.

İşte C# 7.1, bu noktada C#'ın ilk minor release'i olmakta. Visual Studio 2017 kullananlar için 15.3 versiyonu ile beraber gelirken, .NET Core'da ise 2.0 SDK'i ile beraber geliyor. Ancak bu versiyonları edinseniz bile C# 7.1 yenilikleri otomatik olarak kapalı geliyor. Bu nedenle ayrıca açmak için ufak bir ayar yapmaya ihtiyacımız var. Bunun için projemize sağ tıklayıp, Properties seçeneğini seçiyoruz ve sonra da çıkan ekrandan Build tabına geçiyoruz. En altta bir Advanced butonu olacak ve o butona tıkladığımızda ise şöyle bir ekran karşımıza gelecek.

Gördüğünüz gibi Language Version olarak latest major versiyon seçili. Yani default olarak C# 7.0 kullanılıyor. Language version seçeneklerini açtığımızda ise şu şekilde bir liste ile karşılaşıyoruz.

Buradan eğer "latest minor version" seçeneğini seçersek projede artık release olan tüm C# minor versiyonlar updateler geldikçe otomatik olarak kullanımda olacaktır. Bunları yapmak yerine belirli C# versiyonunu seçip projede hep o versiyonun kullanılmasını da sağlayabilirsiniz. Bu ayarı yaparken unutulmaması gereken bir nokta da bu ayarın build konfigürasyonu başına yapılması. Yani yaptığınız değişikliğin hem debug hem de release modda yapılmış olması gerekiyor. Eğer csproj dosyasını manuel editleyerek yapmak isterseniz bunu göz önüne almayı unutmayın. Eğer Visual Studio üzerinden yukarıdaki gibi ayar yapmak istiyorsanız da projeye sağ tıklayıp Properties'e tıkladığınızda gelen ekranda sol yukarıdaki Configuration combobox'ında All Configurations'ı seçmeyi unutmayın.

Şimdi gelelim C# 7.1 özelliklerine...

Async Main

C# 5.0 ile beraber async/await geldiğinden beri özellikle demo yaparken Main metodunun async olamaması ile ilgili hep bir istisna olduğundan bahsediyorduk. Methodu async yapamadığımız için de async bir metot çağırırken bazı farklı kullanımlarda bulunuyorduk. Artık yıllar sonra artık bu durum sona erdi ve Main metot Task veya Task<int> döndürebilir hale geldi. Main metot içerisinde async metotları gönül rahatlığıyla artık await edebiliriz 😃

Default Literals

C# içerisinde bir tipin default değerini alabilmek için default expressionları kullanabiliyorduk.

Örneğin,

var x = default(string);
var y = default(Func<stringintList<string>>); // <---- :(

Sadece string gibi tiplerin default değerini alırken yazım olarak çok zorlanmasak da özellikle kompleks generic tipler olduğunda onları yazmak bazen zor olabiliyordu. Yukarıda verdiğim ikinci örnek bu zorluğa ufak bir örnek olabilir. C# 7.1 ile beraber compiler tipini tahmin edebilidiği durumlarda artık sizin default a ekstra bir tip vermenizi zorunlu kılmıyor. Bu nedenle doğrudan default literal'i kullanabiliyorsunuz. 1-2 kullanım yaparsak örnek olarak...

static async Task Main(string[] args)
{
    Foo(default, 12);
}

static int Foo()
{
    return default;
}

static void Foo(string k, int y)
{

}

Yukarıda görüldüğü gibi metotların alacakları parametrelerde, döndüreceği değerlerde ve daha başka pek çok noktada sadece default literalini kullanabiliriz. Burada kritik nokta compilerın default değerini alacağı tipi tahmin edebilmesi. Tahmin edemediği durumlarda zaten sizden tipi ayrıca belirtmenizi isteyecektir.

Tuple isimlendirme geliştirmeleri

C# 7.0 ile beraber gelen benim en favori özelliğim tuplelar. C# 7.1 ile beraber de tuple içerisindeki fieldların isimlendirilmesi ile ilgili ufak ama güzel bir yenilik geliyor. Tuple kullanımında tuple yaratırken fieldlara dışarıdan isim verebiliyorduk.

Örneğin,

var count = 5;
var sum = 50;
var retVal = (sum: sum, count: count);

Bu şekilde kullanımlarda tuple içerisine koyduğumuz değişkenlerin isimleriyle tuple içerisindeki fieldların ismini büyük oranda aynı oluyor. Dolayısıyla aslında bunu biz belirtmesek de compiler bunu arka planda kendisi yapsa nasıl olur 😃 C# 7.1 ile artık bu mümkün

var count = 5;
var sum = 50;
var retVal = (sum, count);

Console.WriteLine($"Count:{retVal.count} , Sum:{retVal.sum}");

Yukarıda gördüğünüz gibi tuple yaratırken içerisine verdiğimiz değişkenlerin isimleriyle aynı isimde fieldlar yaratılıyor.

Gördüğünüz gibi C# 7.1 içerisinde ufak ama günlük hayatımızda kod yazarken bize yardımcı olacak özellikler gelmekte. Bir sonraki release olacak olan 7.2 release'inde çok daha farklı yenilikler geliyor olacak. Artık bu özellikler için 2 yıl yeni Visual Studio versiyonunu beklemeye gerek yok.



Visual Studio 2017 Kurumsal Lansman C# 7.0 ve Visual Studio 2017 Oturumlarım

Geçtiğimiz hafta Microsoft Türkiye ofisinde kurumsal müşteriler için Visual Studio 2017 lansmanı vardı. Bu lansmanda ben de C# 7.0 ve Visual Studio 2017 yeniliklerinden bahsettim.

Etkinliği Microsoft sadece kendi davet ettiği müşterileri için düzenlediğinden maalesef etklinlik duyurusunu paylaşamadım. Ancak Visual Studio 2017 ile ilgili bir community etkinliği olursa Twitter ve Facebook üzerinden paylaşıyor olurum.

Etkinlik organizasyonunda beni de konuşmacılar içerisine davet eden Daron Yöndem'e teşekkürler.



Visual Studio 2017 Yenilikleri Video Serisi

Bundan önceki Visual Studio versiyonlarında gelen yenilikler ile ilgili zamanında Youtube üzerinde bazı videolar paylaşmıştım. Visual Studio 2017'nin geçtiğimiz günlerde release olmasıyla beraber aynı şekilde videoları da Visual Studio 2017 için çekmeye karar verdim ve bu serinin ilk dört videosu yayında. Aşağıdan hazır olan videoları bulabilirsiniz. Yeni videoları kaçırmamak için Youtube kanalıma abone olmayı unutmayın.

Kurulum Yenilikleri

Live Unit Testing

Debugging Yenilikleri

Kod Navigasyon Yenilikleri



C# 7.0 - Out Variables

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

C# 7.0 ile beraber gelecek olan ufak ama oldukça kullanışlı özelliklerden biri de out variable'lar. Aslında yazının devamını okuyunca bu özellik daha önce gelmedi mi diye de düşünebilirsiniz. Çünkü bu özelliğin ilk olarak C# 6.0 ile beraber gelmesi planlanıyordu ancak Visual Studip 2015 RC versiyonuna geldiğinde C# ekibi bu feature'ı release'e kadar yetiştiremeyeceğini düşündüğü için C# 6.0'dan çıkardı. Şimdi gelelim out variable'ların kullanımına.

out keyword'ü bizim bir metottan birden fazla değer döndürmemiz gerektiği durumlarda başvurduğumuz bir keyword. Örneğin, .NET Framework içerisindeki int.TryParse metoduna bakarsak bu metodun boolean bir değer döndürdüğünü görüyoruz. Aynı zamanda bir de out parametre alıyor ve buradan da parse ettiği değeri metodu çağıran yere geri veriyor. Bir örnek yaparsak,

int result;
string str = "123123";
bool isSucceeded = int.TryParse(str, out result);

</ out keyword'ünün kullanımının en sıkıntılı yanı out parametresi olarak vereceğimiz değişkeni metodu çağırmadan önce tanımlamış olmamız gerekliliği. Çünkü genelde kod yazarken bu tanımlamaları önceden yapmayı unutuyoruz ve out parametresini gördüğümüz anda bir üst satıra geçip o değişkeni tanımlamak zorunda kalıyoruz. Bu da bizi kod yazarken yavaşlatıyor. Artık C# 7.0 ile beraber bu dikkat dağınıklığı ve kod yazarken yavaşlama durumu sona eriyor ve out parametresi olan bir metodu çağırırken inline olarak out parametreyi tanımlayabiliyoruz.

string str = "123123";
bool isSucceeded = int.TryParse(str, out int result);

Bu şekilde gördüğünüz gibi result değişkenini out parametre geçerken tanımlıyoruz ve metot çağırımından sonra da bu değişkeni kullanabiliyoruz. Hatta isterseniz out parametre tanımlarken var keywordünü de kullanbilirsiniz.

string str = "123123";
bool isSucceeded = int.TryParse(str, out var result);

out Parametreden Kurtulma

out parametre kabul eden metotları kullanırken belki de sadece metodun dönüş değerini kullanacağımız ve out parametreyi aslında sadece mecbur kaldığımız için tanımladığımız durumlar olabilir. Mesela, int.TryParse metoduna verdiğiniz string'in bir int value'nun string karşılığı olup olmadığını merak ediyor olabilirsiniz. Dolayısıyla out parametresi olarak verdiğimiz değere hiçbir yerde ihtiyacınız olmayacaktır. Bu gibi durumlar için de yine C# 7.0 out variables syntaxını kullanarak out variable tanımlamaktan kurtulabiliriz. Bunun için out variable'ın adını yazmak yerine _ koyarsak out parametre tanımlamaktan kurtulmuş oluyoruz. Arka plandaki gerekli işlemleri derleyici kendisi hallediyor.

string str = "123123";
if (int.TryParse(str, out var _))
{

}

C# 7.0 içerisindeki belki de en ufak özelliklerden biri out variable'lar. Ancak çözdüğü probleme baktığımızda bu versiyonda en çok kullanılacak olan özelliklerden biri olmaya aday.

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



C# 7.0 - Tuples

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

C# 7.0 ile beraber gelecek olan önemli özelliklerden biri de Tuple'lar. Tuple tiplerine aslında çokta yabancı değiliz. Tuple tipiyle ilk olarak .NET Framework 4.0 ile tanışmıştık. Hani şu içerisinde Item1, Item2, Item3 diye propertyler olan tipler 😃 Çoğu zaman aslında kullanmak istediğimiz ama bu property isimlerinden dolayı kullanma konusunda içimizin rahat olmadığı tipler 😃

Tupleların en önemli kullanım alanları aslında bir metottan birden fazla değer döndürmek zorunda kaldığımız durumlar. C# içerisinde aslında bir metottan birden fazla değer döndürmek istediğimizde out parametrelerini kullanabiliyoruz.

private void Foo(int param1, out int intReturnParam, out string stringReturnParam)
{

}

Ancak out parametreler maalesef async metotlarda kullanılamıyor. Dolayısıyla bu durumda Tuple tipini kullanmak durumunda kalabiliyoruz.

private async Task<Tuple<intstring>> FooAsync(int param1)
{

}

private async void Barrier()
{
    var result = await FooAsync(1);
    Debug.WriteLine($"{result.Item1} : {result.Item2}");
}

Bu durumda da metodu çağıran veya kullanan yazılımcılar aslında bu async metottan ne döndüğü konusunda hiçbir şekilde bilgi sahibi olamıyorlar. Item1, Item2 fieldlarını ne işe yaradığını, hangisinde hangi bilgi olduğunu iyi bir şekilde dökümante etmeniz gerekiyor. Ayrıca mevcut Tuple tipi bir class olduğu için heap allocationa neden oluyor.

Tüm bu nedenlerden dolayı aslında gerçek anlamda Tuple desteği C# 7.0 ile beraber geliyor. Peki C# 7.0'da Tuple'lar nasıl olacak. Gelelim bu kısma.

Not: İlk olarak bu özelliği kullanmadan önce projemize System.ValueTuple nuget paketini eklememiz gerekiyor.

Metotlarda birden fazla değer döndürmek istediğimizde döndüreceğimiz alanların tiplerini ve isimlerini parantez içerisinde yazmamız gerekecek.

static (int count, string value) Foo()
{

}

static Task<(int count, string value)> FooAsync()
{

}

Yukarıda gördüğünüz gibi Foo metodunun dönüş değeri bir tuple ve bu tuple'ın içerisinde count ve value diye 2 tane alan bulunuyor. Ayrıca Task döndüren asenkron metotların da dönüş tipleri gördüğünüz gibi tuple olabiliyor. Bu şekilde tuple dönüş tiplerini tanımladıktan sonra peki metot içerisinde bir tuple nasıl tanımlıyoruz kısmına bakalım.

static(int count, string value) Foo()
{
    var retVal = (count: 1, value: "Foo");
    return retVal;
}

Parantez içerisinde sadece alanın adını ve değerini yazdığınızda da compiler arka planda aynı anonymous objectlerde olduğu gibi alanın tipini kendisi buluyor ve ona uygun tuple tipini yaratıyor. Ayrıca yine tipin compiler tarafından bilindiği durumlarda da tuple'lardaki field adlarının pekte önemi olmuyor. Compiler arka planda ilgili çevrimi kendisi yapıyor. Önemli olan tuple tipindeki alanların tiplerinin uyuşması.

static (int count, string value) Foo()
{
    var retVal = (c: 1, v: "Foo");
    return retVal;
}

Tuple Deconstruction

Bir metottan veya herhangi bir yerden bir tuple döndüğünde o tuple içerisindeki değerleri ayrıştırmak ve metodun devamında ayrıştırılmış halini kullanmak önemli. Bu yüzden tuple içerisindeki alanları ayrıştırıp içerisindeki değerleri değişkenlere atamak için de kolay bir syntax geliyor C# 7.0 ile.

static void Main(string[] args)
{
    var (count, value) = Foo();
}

static (int count, string value) Foo()
{
    var retVal = (c: 1, v: "Foo");
    return retVal;
}

Main metodunda göründüğü gibi Foo metodundan dönen tuple tipi içerisindeki alanları count ve value ismindeki local değişkenlere atamasını yapabiliyoruz. Böylece aslında tuple tipleri tamamen görünmez bir şekilde kalabiliyorlar. Yani siz bir metottan tuple döndüğünü biliyorsanız, bu tuple içerisindeki alanları hemen hızlıca lokal değişkenlere alıp kodunuzu temiz tutabilirsiniz.

Bazen de metotlardan dönen tuple içerisindeki sadece belirli alanlar işinize yarayabilir. Bu durumda tuple içerisindeki tüm alanları deconstruct etmek yerine istediğiniz değerleri deconstruct edip değişkenlere atayabilirsiniz. Bunun için yukarıda gösterdiğim syntax'ı kullanarak değişken ismi yerine _ koymanız yeterli.

static void Main(string[] args)
{
    var (count, _) = Foo();
}

static (int count, string value) Foo()
{
    var retVal = (c: 1, v: "Foo");
    return retVal;
}

C# 7.0 ile beraber gelen tuple'ların Framework içerisinde bulanan Tuple'lardan bazı farkları var. Bunlardan ilki C# 7.0 tuple'larının struct olması. Böylece bu tupleların yaratılmaları daha az maliyetli. Ayrıca C# 7.0 tuple'ları mutable. Yani bir tuple yarattıktan sonra fieldın değerini değiştirebilirsiniz. Ancak .NET Framework içerisindeki Tuple tipleri immutable. Yani yarattıktan sonra fieldın değerini sadece okuyabilirsiniz, değiştiremezsiniz.

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



C# 7.0 - Pattern Matching

Şu ana kadar C# 7.0 ile beraber gelmesi planlanan pek çok özelliği inceledik. Bu blog postu da saymazsak incelemediğimiz sadece 3 özellik kalıyor. BU özellikler pattern matching, out var ve tuples.

Bu blog postta ise pattern matching özelliğine bakacağız. C# 7.0 ile beraber gelecek en büyük özelliklerden biri olan pattern matching ile ilgili çektiğim videoyu aşağıdan izleyebilirsiniz.

Video Linki : https://www.youtube.com/watch?v=HzSh0PFBfoQ

Pattern Matching Kod Örnekleri: https://github.com/ilkayilknur/csharp-7-new-features/tree/master/PatternMatching

Görüşmek Üzere



C# 7.0 Kod Örnekleri

C# 6.0 zamanlarında özellikleri anlatan kod örneklerini Github üzerinden paylaşmıştım. C# 7.0 versiyonu da artık yavaş yavaş belirginleşmeye ve release olmaya doğru giderken benzer tarzda örnekleri C# 7.0 içinde koymaya karar verdim.

İlgili örneklere https://github.com/ilkayilknur/csharp-7-new-features adresinden ulaşabilirsiniz. Hatta ekleyebileceğiniz özel kullanım durumları da varsa pull request gönderebilirsiniz.

Görüşmek Üzere



C# 7.0 - Digit Separators

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Not : Bu makaledeki örnekleri denemek için gereken ortam kurulum bilgisini buradan alabilirsiniz.

C# 7.0 ile beraber gelmesi planlanan ufak özelliklerden biri de digit separatorler. Digit separatorler ile numeric değer tanımlamaları sırasında istediğiniz bölümde basamakları ayırabiliyorsunuz. Böylece kod yazarken tanımlamış olduğunuz numeric değişkenlerin taşıdıkları değerler daha okunabilir olurken hem de siz tanımlama esnasında basamakları ayırabildiğiniz için hata yapma olasılığınız daha düşük oluyor. Digit separator olarak ise _ kullanıyoruz.

Örneğin,

int x = 1_000_000;
double y = 1_00.0_9;

Digit separatorlerin bir diğer kullanım alanı da binary literal'lar. Binary literal tanımlamaları esnasında da digit separatorleri kullanmamız mümkün.

Örneğin,

int x = 0b11_00_0_01;
double y = 0b1_00;

Bu ufak özellikle ilgili yazımızda bu kadar. Bir sonraki C# 7.0 özelliğinde görüşmek üzere...



C# 7.0 - Binary Literals

Bu makaleye Github üzerinden katkıda bulunabilirsiniz.

Not : Bu makaledeki örnekleri denemek için gereken ortam kurulum bilgisini buradan alabilirsiniz.

C# 7.0 ile beraber gelmesi muhtemel özelliklerden biride Binary Literals özelliği. Aslında C# design meetinglerini takip edenler için bu özellik süpriz bir özellik değil. Çünkü aslında aynı özellik C# 6.0'da da planlanıyordu ancak release döneminde bu özellik ne yazık ki C# 6.0'a dahil edilmedi.

İşin magazin tarafını bir kenara bırakırsak :) binary literals ile kod içerisinde binary olarak tanımlamalar yapabiliyorsunuz. Bunu yapmak için binary ifadenin başına 0b veya 0B yazmanız yeterli.

Örneğin,

static void Main(string[] args)
{
    int x = 0b1100001;
    double y = 0b100;
}

Gördüğünüz gibi kullanımı oldukça basit. Gelelim bu özellik nerelerde işimize yarayacak kısmına. Enumlara Flags attribute'ünü ekleyip 2'nin üssü bir biçimde değerler verdiğimizde enumlar üzerinde bitwise operasyonlar yapabiliyoruz. (Enumlar üzerinde bitwise operasyonlar ile ilgili yazmış olduğum yazıyı inceleyebilirsiniz. http://www.ilkayilknur.com/coklu-enum-degerleriyle-calismak) Burada 2'nin üssü değerleri verirken binary literalleri kullanabiliriz. Böylece hızlı bir şekilde ve daha az hata olasılığıyla hızlı bir şekilde kodumuzu yazabiliriz.

[Flags]
enum Colors
{
    Red = 0b1,
    Green = 0b10,
    Blue = 0b100
}

Gördüğünüz gibi binary literallerin bana göre en önemli kullanım alanı burası olacak. Bunun yanında C# ekibi binary ifadeleri öğrenen developerların da C# içerisinde eğitim amaçlı binary literalleri kullanacaklarını düşünüyorlar.

C# 7.0 binary literals özelliğiyle ilgili yazımız bu kadar. Zaten gördüğünüz gibi oldukça ufak bir özellik :) Bir sonraki yazıda görüşmek üzere...