C# 7

Paylaş

.NET platformunun ana dili olan C# diline C# 7 ile birlikte gelen Pattern matching, Tuples, Local functions, Digit separators, Binary literals, Out variables ile ilgili bilgiler yer alıyor.

C# 7 ile gelen özelliklere bakmadan önce C# 6 ile gelen özelliklere buradan bakabilirsiniz.

C# 7.0

Pattern matching

C# 7 ile birlikte değer kontrolünü daha az komut ile yaparak değişkene atayan pattern matching özelliği gelmiştir.

using System;

class Person {
    public Guid Id { get; } = Guid.NewGuid();
    public string FirstName { get; } = "Yusuf";
    public string LastName { get; } = "Sezer";
}

class Program {

    public static void Main(string[] args) {
        Person yusuf = new Person();
        Yazdir(yusuf);
    }

    public static void Yazdir(object nesne) {
        if(nesne is null)
            Console.WriteLine("Nesne null");
        else if(nesne is Person p)
            Console.WriteLine($"{p.FirstName} {p.LastName}");
        else
            Console.WriteLine("Nesne tanımlanamadı.");
    }
}

Örnekte görüldüğü üzere eşleşen değişkenin değeri if içerisinde atanmıştır.

using System;

class Person {
    public Guid Id { get; } = Guid.NewGuid();
    public string FirstName { get; } = "Yusuf";
    public string LastName { get; } = "Sezer";
}

class Program {

    public static void Main(string[] args) {
        Person yusuf = new Person();
        //object deger = yusuf;
        object deger = 1453;

        switch(deger) {
            case int sayi:
                Console.WriteLine("int, değer = " + sayi);
            break;
            case true:
            case false:
                Console.WriteLine("bool");
            break;
            case Person p when p.FirstName =="Yusuf":
                Console.WriteLine("Hoşgeldin Yusuf");
            break;
            case Person p:
                Console.WriteLine("person");
            break;
            default:
                Console.WriteLine("Bulunamadı");
            break;
        }
    }
}

Örnekte görüldüğü üzere switch yapısı pattern matching ile daha yetenekli hale gelmiş.

Tuples

C# içerisinde yer alan tuple kullanımı C# 7 ile birlikte daha da geliştirilmiştir.

using System;

class Program {

    public static void Main(string[] args) {
        Tuple<int, string, string> yusuf = new Tuple<int, string, string>(1, "Yusuf", "Sezer");
        Console.WriteLine($"{yusuf.Item1} {yusuf.Item2} {yusuf.Item3}");

        var sonuc = Bilgiler();
        Console.WriteLine($"{sonuc.Item1} {sonuc.Item2} {sonuc.Item3}");
    }
    
    public static (int, string, string) Bilgiler() {
        return (1, "Yusuf", "SEZER");
    }
}

Tuple sayesinde class veya struct tanımına ihtiyaç duymadan verileri saklayan bir tür tanımlamış olduk.

Böylece tuple özelliği ile birden fazla değer döndüren metotlar tanımlayabildik.

Deconstruction

Sınıf içerisinde yer alan özelliklere sınıf.ozellik olarak erişim sağlıyoruz.

Deconstruction özelliği ile sınıf içerisindeki özelliklere doğrudan erişim sağlayabiliriz.

using System;

class Person {
    public Guid Id { get; } = Guid.NewGuid();
    public string FirstName { get; } = "Yusuf";
    public string LastName { get; } = "Sezer";

    public void Deconstruct(out string FirstName, out string LastName) {
        FirstName  = this.FirstName;
        LastName = this.LastName;
    } 
}

class Program {

    public static void Main(string[] args) {
        var(FirstName, LastName) = new Person();
        Console.WriteLine($"{FirstName} {LastName}");
    }
}

Örnekte görüldüğü üzere Deconstruct metodu ile sınıf içerisinde yer alan değerleri out ile dışarı aktarmış olduk.

Local functions

C# 7 ile birlikte gelen local functions veya yerel fonksiyon özelliği ile metot, özellik ve tanımlanan yerel fonksiyonun içerisinde fonksiyon tanımlamamıza imkan verir.

using System;

class Program {

    public static void Main(string[] args) {
        int sonuc = Topla(10, 20);
        Console.WriteLine($"Sonuç: {sonuc}");

        int Topla(int s1, int s2) => s1 + s2;  // lambda functions
    }
}

Bu özellik sayesinde sadece tek bir metot içerisinde kullanılan fonksiyon, metot içerisinde tanımlanarak karmaşıklığını önlemektedir.

Digit separators

C# 7 ile birlikte gelen digit separators özelliği ile uzun sayıları daha okunabilir yazabiliriz.

using System;

class Program {

    public static void Main(string[] args) {
        int i = 1_00_000;
        double f = 1_00_000;
        Console.WriteLine(i);
        Console.WriteLine(f);
    }
}

Binary literals

C# 7 ile gelen binary literals özelliği ile ikilik sayı sisteminin kullanımı daha kolay hale geldi.

using System;

class Program {

    public static void Main(string[] args) {
        int a = 0b1010;
        int b = 0b1010_1111_01010;
        int c = 0x00A;
        Console.WriteLine(a);
        Console.WriteLine(b);
        Console.WriteLine(c);
    }
}

Ref locals and Ref returns

C# 7 ile birlikte ref anahtar kelimesinin kullanımı daha da genişletilmiştir.

using System;

class Program {

    public static void Main(string[] args) {
        int [] sayilar = {1, 2, 3};
        Yazdir(sayilar);
        ref int bulunanSayi = ref SayiBul(sayilar, 3);
        Console.WriteLine($"Sayı bulundu değeri: {bulunanSayi}");
        bulunanSayi = 1453;  // bulunan sayı değiştirildi.
        Yazdir(sayilar);
    }

    public static ref int SayiBul(int[] sayilar, int arananSayi) {
        for(int i = 0; i < sayilar.Length; i++)
            if(sayilar[i] == arananSayi)
                return ref sayilar[i];
        throw new Exception("Sayı bulunamadı.");
    }

    public static void Yazdir(int[] sayilar) {
        foreach(int sayi in sayilar)
            Console.WriteLine(sayi);
    }
}

Ref returns özelliği ile bulunan değerin referansıyla değerini değiştirdik.

Ref hakkında detaylı bilgi için C# ref ve out Nedir? Kullanımı yazıma bakabilirsin.

using System;

class Program {

    public static void Main(string[] args) {
        int [] sayilar = {1, 2, 3};
        Console.WriteLine(sayilar[1]);
        
        ref int sayi = ref sayilar[1];
        sayi = 1453;
        Console.WriteLine(sayilar[1]);
    }
}

Benzer şekilde sınıf içerisinde yer alan değerleri referans ile değiştirdik.

C# içerisinde yer alan ref ile ilgili bilgi almak için C# ref ve out yazıma bakabilirsiniz.

Expanded expression bodied members

C# 6 ile birlikte gelen expression bodied özelliği genişletilerek getter, setter, kurucular ve yıkıcılar içinde kullanılabilir hale geldi.

using System;

class Person {
    public Guid Id { get; } = Guid.NewGuid();
    public string FirstName { get; } = "Yusuf";
    public string LastName { get; } = "Sezer";
    public Person(string firstname, string lastname) => (FirstName, LastName) = (firstname, lastname);
    public void Yazdir() => Console.WriteLine($"{FirstName} {LastName}");
    ~Person() => Console.WriteLine("Nesne silindi.");
}

class Program {

    public static void Main(string[] args) {
        Person sinan = new Person("Sinan", "Sezer");
        sinan.Yazdir();
    }
}

C# 6 ile gelen özelikler için C# 6 yazıma bakabilirsiniz.

Out variables

C# 7 öncesinde int, double, DateTime gibi veri türlerine ait TryParse metodu için önceden değişken tanımlayıp kullanıyorduk.

C# 7 ile birlikte artık değişken tanımını metot kullanımı ile yapabiliriz.

using System;

class Program {

    public static void Main(string[] args) {
        // C# 7 öncesi
        string tarihimiz = "01-01-2000";
        DateTime tarih;
        if(DateTime.TryParse(tarihimiz, out tarih)) {
            Console.WriteLine(tarih);
        }

        // C# 7
        if(DateTime.TryParse(tarihimiz, out DateTime tarih1)) {
            Console.WriteLine(tarih1);
        }
    }
}

Throw expressions

C# 7 ile birlikte istisnaların oluşturulması daha kolay hale geldi.

using System;

class Person {};

class Program {

    public static void Main(string[] args) {}

    // C# 7 öncesi
    public static void BirHataVar(Person person) {
        if(person == null)
            throw new ArgumentNullException();
        Person p = person;
    }
    
    // C# 7
    public static void YeniBirHataVar(Person person) {
        Person p = person ?? throw new ArgumentNullException();
    }
}

Discards

C# 7 ile birlikte gelen discards özelliği kullanılmayan değişkenleri iptal etmek için kullanılır.

Örneğin aşağıdaki gibi bir kullanımda tarih değerine ihtiyacımı yok ancak kullanabiliyoruz.

using System;

class Program {

    public static void Main(string[] args) {
        string tarihimiz = "01-01-2000";
        if(DateTime.TryParse(tarihimiz, out DateTime tarih)) {
            Console.WriteLine("Doğru bir tarih.");
        }
        Console.WriteLine(tarih);
    }
}

Uzun komutlarda bunun gibi komutlar birden fazla değişkenin oluşmasına ve komutların karışmasına neden olur.

Değişkeni iptal etmek için _ kullanmak yeterli olacaktır.

using System;

class Program {

    public static void Main(string[] args) {
        string tarihimiz = "01-01-2000";
        if(DateTime.TryParse(tarihimiz, out DateTime _)) {
            Console.WriteLine("Doğru bir tarih.");
        }
    }
}

C# 7.1

async Main

Özellik Main metodunda async anahtar kelimesini kullanmayı sağlar.

using System;

class Program {

    public static async Task Main(string[] args) {
        // C# 7.1 öncesi
        Task.Run(() => {
            Console.WriteLine("Merhaba C#");
        }).GetAwaiter().GetResult();

        // C# 7.1 sonrası
        await Task.Run(() => {
            Console.WriteLine("Merhaba C# 7.1");
        });
    }

}

Özellikle birlikte kullanılabilir Main metot imzaları aşağıdaki gibidir.

public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }

Özellik await ile daha kısa kod yazmayı arka planda üretilen gizli Main metodu ile sağlar.

Target-typed “default” literal

Özelllik default anahtar kelimesini tür belirtmeden kullanmayı sağlar.

using System;

class Program {

    public static void Main(string[] args) {
        // C# 7.1 öncesi
        int myNumber = default(int);

        // C# 7.1 sonrası
        int myNewNumber = default;
    }

    // C# 7.1 öncesi
    static decimal MyMethod(long myLongNumber = default(long)) {
        return default(decimal);
    }

    // C# 7.1 sonrası
    static decimal MyNewMethod(long myLongNumber = default) {
        return default;
    }

}

Kod derlendiğinde, derleyinici derleme zamamında tür çıkarımı yaparak önceki sürüme benzer sonuç üretecektir.

Infer tuple names

Özellik diğer bilinen adıyla Tuple Projection Initializers Tuple öğe adlandırmasını değişken adından çıkarım yapmayı sağlar.

using System;

class Program {

    public static void Main(string[] args) {
        // C# 7.1 öncesi
        string firstName = "Yusuf";
        string lastName = "Sezer";

        var yusuf = (firstName: firstName, lastName: lastName);
        Console.WriteLine($"{yusuf.firstName} {yusuf.lastName}");

        // C# 7.1 sonrası
        var yusufNew = (firstName, lastName);
        Console.WriteLine($"{yusufNew.firstName} {yusufNew.lastName}");

    }

}

Generic Pattern-Matching

C# 7.0 ile birlikte gelen Pattern matching özelliğinin kullanımı genişletilerek Generic türler içinde kullanımı sağlar.

using System;

class Program {

    public static void Main(string[] args) {
        string input = "Yusuf Sezer";
        Console.WriteLine(Print(input));
    }

    static string Print<T>(T input) {
        switch (input) {
            case int i:
                return "int";
            case string s:
                return "string";
            default:
                return "unknown";
        }
    }

}

NOT: Örnekteki kod C# 7.1 öncesinde derleyici hatası verecektir.

C# 7.1 sürümü yeni eklenen özellikler ile daha az kod ile daha fazla iş yapmayı ve C# 7.0 ile gelen özellik desteğini genişletmiştir.

C# 7.2

Leading Digit Separator

C# 7.0 ile gelen Digit separators ve Binary literals özelliklerini kullanımı genişletilerek ayracın başta kullanılması sağlanmıştır.

using System;

class Program {
    public static void Main(string[] args) {
        // C# 7.2 öncesi
        int a = 0b1010;
        int b = 0b1010_1111_01010;
        int c = 0x00A;
        Console.WriteLine(a);
        Console.WriteLine(b);
        Console.WriteLine(c);

        // C# 7.2 sonrası
        int d = 0b_1010;
        int e = 0b_1010_1111_01010;
        int f = 0x_00A;
        Console.WriteLine(d);
        Console.WriteLine(e);
        Console.WriteLine(f);
    }

}

Non-trailing named arguments

Özellik C# 4 birlikte gelen Named Arguments özelliğini genişleterek belirli parametreden sonra devam etmesini sağlamaktadır.

using System;

class Program {
    public static void Main(string[] args) {
        MyMethod(1, "Yusuf", "Sezer"); // C# 7.2 öncesi
        MyMethod(id: 1, firstName: "Yusuf", lastName: "Sezer"); // C# 7.2 öncesi
        MyMethod(1, firstName: "Yusuf", "Sezer"); // C# 7.2 sonrası
    }

    static void MyMethod(int id, string firstName, string lastName) {
        Console.WriteLine($"{id} {firstName} {lastName}");
    }

}

Örnekte ikinici isimlendirilmiş parametre sonrası sıradaki parametreden devam etmiştir.

private protected

Yeni erişim belirleyici (Access modifiers) sınıftaki özellik ve metotlara sadece aynı Assembly altından erişimi sağlar.

namespace Library {
    public class Human {
        private protected int counter = 0;
    }

    public class Person : Human {
        void CountUp() {
            Human human = new Human();
            // human.counter++; // nesne üzerinden erişim yok
            counter++; // kalıtım ile erişim
        }
    }
}

Başka bir Assembly altında kalıtım alınarak genişletildiğine özellik ve metotlara erişim olmayacaktır.

namespace Other {
    class Engineer : Library.Human {
        void CountUp() {
            Human human = new Human();
            // human.counter++; // nesne üzerinden erişim yok
            counter++; // Farklı assembly erişim yok
        }

    }
}

Özellik ile birlikte kullanılabilir erişim belirleyicileri aşağıdaki gibidir.

  • public
  • protected
  • internal
  • private
  • protected internal
  • private protected

Stackalloc Array Initializers Of Spans

Özellik stackalloc anahtar kelimesiyle oluşturulan bellek alanını unsafe anahtar kelimesi kullanmadan Span ve ReadOnlySpan ile ifade etmeyi sağlar.

using System;

class Program {

    public static void Main(string[] args) {
        // C# 7.2 öncesi
        unsafe
        {
            int* numberPtr = stackalloc int[2];
        }

        // C# 7.2 sonrası
        Span<int> numbers = stackalloc int[2];
        ReadOnlySpan<int> numbers2 = stackalloc int[2];
    }

}

NOT: Span ve ReadOnlySpan sınıfları byte türünden ardışık bellek alanına erişmek-yönetmek için kullanılan sınıflardır.

ref conditional expression

Özellik referans türünden ifadeleri üçlü koşul (ternary operator) ile kullanmayı sağlar.

using System;

class Program {

    public static void Main(string[] args) {
        int[] numbers = { 1, 2 };

        // C# 7.2 öncesi
        ref var secim = ref Secim<int>(1 == numbers[0], ref numbers[0], ref numbers[1]);

        // C# 7.2 sonrası
        ref var secim2 = ref (1 == numbers[0] ? ref numbers[0] : ref numbers[1]);
        Console.WriteLine(secim2);

    }

    static ref T Secim<T>(bool condition, ref T secimTrue, ref T secimFalse) {
        if (condition)
            return ref secimTrue;
        else
            return ref secimFalse;
    }

}

NOT: Önceki sürümlerde geçici çözüm olarak metot kullanılmıştır.

Readonly references

Özellik referans değerlerini sadece okunabilir olarak göndermeyi in, ref readonly, readonly struct, ref-in extension methods, ref readonly locals ve ref conditional expressions ile sağlar.

using System;

class Program {

    public static void Main(string[] args) {
        Yazdir("Yusuf Sezer");
    }

    static void Yazdir(in string metin) {
        // metin = "asd"; // readonly hata verir
        Console.WriteLine(metin);
    }

}

ref conditional expression özelliğindeki örneğin readonly kullanılarak yazılmış hali aşağıdaki gibidir.

using System;

class Program {

    public static void Main(string[] args) {
        int[] numbers = { 1, 2 };

        // C# readonly locals
        ref readonly var secim = ref Secim<int>(1 == numbers[0], ref numbers[0], ref numbers[1]);

        // C# readonly locals - ref conditional expressions
        ref readonly var secim2 = ref (1 == numbers[0] ? ref numbers[0] : ref numbers[1]);
        Console.WriteLine(secim2);
    }

    // # ref readonly returns
    static ref readonly T Secim<T>(bool condition, ref T secimTrue, ref T secimFalse) {
        if (condition)
            return ref secimTrue;
        else
            return ref secimFalse;
    }

}

readonly structs

Özellik struct veya yapıları sadece okunabilir olmasını sağlar.

readonly struct Person {
    public Guid Id { get; }
    public string FirstName { get; }
    public string LastName { get; }
    // public byte Age { get; set; } // readonly struct - set; hata verir.
}

NOT: Özellik değer ataması yapan set; ifadesi kullanımında hata verir.

ref structs

Özellik readonly structs özelliğinde farklı olarak içerisindeki öğelere değer atamaya imkan verir.

ref struct Person {
    public Guid Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public byte Age { get; set; }
}

C# 7.2 sürümü ile gelen özelliklerin bir çoğu yönetilemeyen belleğe erişimi unsafe anahtar kelimesi kullanmadan sağlayarak yüksek performans gerektiren uygulamalar için alt yapı sağlamıştır.

C# 7.3

Ref Local Reassignment

Özellik ref anahtar kelimesiyle tanımlı değişkenlere yeniden başka bir değer atamayı sağlar

using System;

class Program {

    public static void Main(string[] args) {
        int sayi1 = 10;
        int sayi2 = 20;
        ref int enBuyuk = ref sayi1;
        if (sayi2 > sayi1)
        {
            enBuyuk = ref sayi2; // ref reassignment
        }
        Console.WriteLine(enBuyuk);
    }
}

Unmanaged type constraint

Özellikle gelen unmanaged anahtar kelimesi kısıtı generic tür olarak sadece yönetilmeyen türlerin kullanımı sağlayarak yönetilen türlerin kullanımı kısıtlar.

using System;

class Program {

    public static void Main(string[] args) {
        Yazdir<int>(1);
        Yazdir<long>(1L);
        // Yazdir<string>("Yusuf"); // Yönetilen tür izin verilmez.
    }

    static void Yazdir<T>(T value) where T : unmanaged // Unmanaged type constraint
    {
        Console.WriteLine(value);
    }
}

Auto-Implemented Property Field-Targeted Attributes

Özellik getter-setter Property için Attribute eklemeyi sağlar.

[Serializable]
public class Person {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [field: NonSerialized]
    public SecureString Password { get; set; }
}

Enum and Delegate type parameter constraint

Özellikle birlikte kısıtlayıcılara Enum ve Delegate eklenmiştir.

public static T CalistirDelegate<T>(T t) where T : Delegate { // Delegate kısıtı
    return t;
}

public static T CalistirEnum<T>(T t) where T : Enum { // Enum kısıtı
    return t;
}

Expression variables in initializers

C# 7 ile birlikte gelen Pattern matching özelliği değişkenlere değer atamayı sağlayarak genişletilmiştir.

private int arrows = weapon is Bow bow ? bow.Arrows : 0;
private int number = Int32.TryParse(input, out int value) ? value : 0;

Tuple equality

C# 7 ile birlikte gelen Tuple türüne eklenen == ve =! operatörleri karşılaştırma yapmayı kolaylaştırmıştır.

using System;

class Program {
    public static void Main(string[] args){
        (int Id, string FirstName, string LastName) yusuf = (1, "Yusuf", "Sezer");
        (int Id, string FirstName, string LastName) sefa = (2, "Sefa", "Sezer");

        Console.WriteLine(yusuf == sefa);
        Console.WriteLine(yusuf != sefa);
    }
}

Stackalloc array initializers

Özellikle birlikte stackalloc ile dizi tanımlama imkanı gelmiştir.

using System;

class Program {
    public static void Main(string[] args) {
        Span<int> oddNumbers = stackalloc int[5] { 1, 3, 5, 7, 9 };
        Span<int> evenNumbers = stackalloc int[] { 2, 4, 6, 8 };
        Span<int> primerNumbers = stackalloc[] { 2, 3, 5, 7 };

        unsafe {
            int* ptr = stackalloc int[5] { 1, 2, 3, 4, 5 };
            int* ptr2 = stackalloc int[] { 1, 2, 3, 4, 5 };
            int* ptr3 = stackalloc[] { 1, 2, 3, 4, 5 };
        }
    }
}

C# 7.3 sürüm C# 7 sürümünün son sürümü olarak C# 7, 7.1 ve 7.2 ile gelen özelliklerin kullanımı genişletmiştir.

C# 7.0, 7.1, 7.2, 7.3 ile birlikte gelen özellikler daha az kod yazarak daha fazla işlem yapmayı ve fonksiyonel programlama dillerinde yer alan özellikleri getirmiştir.

C# 7 sürümlerinde yüksek performans gerektiren ve belleğe doğrudan erişmeyi unsafe parametresi olmadan çalıştırmayı sağlayan özellikler eklenmiştir.

Yeni gelen özellikleri Visual Studio 2017, .NET Core 2.0 ve roslyn derleyicisi ile kullanabilirsiniz.

.NET Derslerine buradan ulaşabilirsiniz.

Hayırlı günler dilerim.


Bunlarda ilgini çekebilir


Destek almak için tıklayın.