Csharp 9 ve sonrası
Tags: csharp, dotnet, newthings, programming
Published: 2020-09-06 13:18:35

*Bu yazım daha önce hazırlanmış [bu blogda](https://www.algomedi.com/post/c-9-0) da yayınlanmıştır.*


Merhaba, bu blog yazısında C# 9 ile gelmesi beklenen yeni özelliklere bir bakış atacağız ve bazen de bu özellikler ile ilgili kişisel düşüncelerimi paylaşacağım. Lütfen eksik\hatalı bulduğunuz kısımları yorum\e-posta yolu ile belirtmekten çekinmeyin. 

C# 9 ile gelmesi beklenen özellikleri yazarken https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md  adresindeki dil özelliklerinin durumunun paylaşıldığı sayfadan yararlanacağım. Özellikler için son durum, güncelemeler ve daha fazla bilgi için ziyaret edebilirsiniz. 

##Hedef Türünde new İfadesi 

Var  anahtar sözcüğü(keyword) ile kullanılan tür çıkarsaması(type inference) sadece yerel(local) değişkenler ile kullanılabiliyordu. Artık sınıfa ait alanlar için de tür çıkarsaması kullanılabilecek. Ancak farklı söz dizimi ile. 

*Örnek olarak*
```csharp
    public class C 
    { 

        private readonly static Point point = new(); 
        public Point Target => new (4,5); 
        //    var newList = new List<int>(); Hala sözdizimi hatası 

  
        public static void Main(string[] a) 
        { 
            List<int> list = new(); 
            var newList = new List<int>(); 
        } 
    } 
     
    public class Point 
    { 
        public double X {get;set;} 
        public double Y {get;set;} 
        public Point(){} 
        public Point(double x, double y) 
        { 
            (X,Y) = (x,y); 
        } 
    } 
```
Bu yeni tür çıkarsama sözdizimi hem yerel hem de sınıfa ait üyelerde kullanılabilecek. 

 

Var tür çıkarsamasının kullanılmamasının en büyük nedenlerinden biri derleyicide gerçekleştirimin zor olması kaynaklı olarak gözüküyor(Derleyicinin bazı kısımları buna uygun olarak yeniden yazılması gerekecekmiş.). Ayrıca  apideki tür değişimleri daha belirgin olarak görüleceğini de eklemişler. 

 

Kişisel görüşüm yerel değişkenlerde de fonksiyon değerinin sonucu için kullanılmayacaksa ve bu yeni söz dizimin kullanılayamacağı başka alanlarda kullanılmaacak ise bu kullanımın daha okunabilir olduğunu ve ide kullananlar için daha doğru değişken adı önerilerini verebileceğini düşünüyorum 

###### Bazı şeyler
 *throw new şeklinde kullanılabilecek(System.Exception) 
 *ref olarak belirtilemeyecek. 
 *Binary operatörler ile kullanılamayacak. 
 *...

##Tür bildiriminde ‘ref’ ve ’partial’ olarak nitelendirmekte sıralama rahatlığı 

Önceden örneğin struct bildirimi yaparken ref partial struct olarak belirtmek gerekiyor idi.(ref hemen partialdan önce olacak şekilde) Ancak artık ref partial sıralamasını serbest bir biçimde bildirebileceğiz. 

##Parametre null mı doğrulamasını kolaylaştırma 
Fonksiyonsa basit bir belirtme ile artık parametre de geçilen değerin null olup olmadığı doğrulaması yapılacabilecek. 
*Örnek olarak*  
```csharp
// Önce 
void Insert(string s) 
{ 
  if (s is null) 
    throw new ArgumentNullException(nameof(s));
  ... 
} 

// Sonra 
void Insert(string s!) 
{ 
  ... 
} 
```

##Yerel ilklemeleri geç 

Bazı durumlarda değişken kullanılmayacak ve/veya kullanılacağı zaman ise zaten başka bir değer ile setlenecektir. Bu gibi zamanlarda bazen derleyici bu durumu yakalayamaz ve yine de değişleni ilklendirir. Bu da anlamsal olarak bir zararı olmasa bile performans kaybına neden olur. Böyle durumlar için `SkipLocalsInit` Attribute’ü ekleniyor. Bu sayede attribute ile belirtimiş üyeler ilklendirilmeyecek. 

##Artık lambda parametreleri 
Eklenen discard özelliği lambdalarda da kullanılabilecek bir biçimde genişletiliyor. 
*Örnek olarak*
```csharp
(_, _) => 1, (int _, string _) => 1, void local(int _, int _) 
```
##Native Int’ler 
Int karşılığında => nint 

uint karşılığında ise => nuint türleri ekleniyor. Bu türler int gibi genel tür olmadığı gibi işlemci üzerinde büyüklükleri değişebilecek değerler. Bu taşınabilirliğe sıkınt getirdiği gibi performans da getirmekte. 

##Yerel Fonksiyonlarda Attribute kullanabilme 

Yerel fonksiyonlarda da artık Methodlardaki gibi attribute kullanılabilecek.

*Örnek olarak*
```csharp
 public class Startup
 {
        ...
        
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting(routes =>
            {
                Task SayHello(HttpContext context)
                {
                    return context.Response.WriteAsync("Hi there!");
                }
                routes.Map("/", SayHello);
                
                [Authorize(Roles = "admin")]
                Task AdminsOnly(HttpContext context, [FromServices] ApplicationContext db)
                {
                    // get message from db and write it out
                }
                routes.Map("/secret", AdminsOnly);
            });

            app.UseAuthentication();
            app.UseAuthorization();
        }
    }
```
Örnek [buradan](https://gist.github.com/rynowak/4d4738a57fb482952056ca67573f1d50) alınmıştır.

##Fonksiyon pointerlarının eklenmesi 
Artık Csharpta da unsafe kod olarak fonksiyon pointerları kullanılabilecek.  
*Örnek olarak*
```csharp
unsafe class Util 
{ 
    public static void Log() { } 
    void Use() 
{ 
        delegate*<void> ptr1 = &Util.Log; 

        // hata: "delegate*<void>"  türü "delegate*<int>" türü ile uyumlu değil; 
        //delegate*<int> ptr2 = &Util.Log; 
        // Sorunsuz. void*'e dönüşüm her zaman izin verilmiştir. 

        void* v = &Util.Log; 
   } 
} 
```
##Pattern Matching Geliştirmeleri 
###Tür Deseni 
Artık direkt olarak basitçe türün kendisini belirterek yanınca discard(_) belirteci olmadan kullanılabiliyor. 
```csharp
void M(object o1, object o2) 
{ 
    var t = (o1, o2); 
    if (t is (int, string)) {} //  o1 int ve o2 string ise

    switch (o1) 
    { 
        case int: break; // o1 int ise
        case System.String: break; // o1 string ise
    } 
} 
```
###İlişkisel eşleme 
Artık <, >, >=, <= operatörler aşağıdaki örnekteki gibi kullanılabilecek. Ancak yalnızca const değeler ile kullanılabilecek. 

```csharp
 public static LifeStage LifeStageAtAge(int age) => age switch 
    { 
        < 0 =>  LiftStage.Prenatal, 
        < 2 =>  LifeStage.Infant, 
        < 4 =>  LifeStage.Toddler, 
        < 6 =>  LifeStage.EarlyChild, 
        < 12 => LifeStage.MiddleChild, 
        < 20 => LifeStage.Adolescent, 
        < 40 => LifeStage.EarlyAdult, 
        < 65 => LifeStage.MiddleAdult, 
        _ =>    LifeStage.LateAdult, 
    }; 
```
##Desen Birleştirici 
2 farklı desen eşleşmesi artık and ve or, not ifadeleri ile birleştirilebilecek. And ifadesi hesaplanırken or işlemine göre öncelikli olarak hesaplanıyor. Ancak parantezler yardımıyla öncelikler değiştirilebilir. 
```csharp
bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z'); 
```
##Static lambda 
Lambda kullanılırken yanlışlıkla yerel değerlere(`this` ve `base`’e) erişiminin engellenmesi amaçlı bir özellik. ```csharp
int y = 10;
someMethod(static x => x + y); // hata! 

const int y = 10;
someMethod(static x => x + y); // sorunsuz:-)  
```

##Init Only Setters 
Property tanımlarının nesne ilklendirmeler ile(`new A{Property = “A”}`) çalışabilmesi için mutable(değeri değişebilir) olmak zorundadır. Immutable(sabit) tanım ile nesne ilklendirme kullanılabilmesi için set ve get harici üçüncü bir erişici tanımlanıyor. Bu tanım sayesinde property bir kez setlendikten sonra tekrar setlenemeyecek ve nesnenin immutable olarak kullanılabilmesine olanak sağlanacaktır. 
```csharp
public class Person 
{ 
    public string FirstName { get; init; } 
    public string LastName { get; init; } 
} 
```

##Records
Record tipleri referans tipindedir. Varsayılan olarak immutable veri tanımlamak için kullanılır.
 
Record tanımlanırken varsayılan olarak değer üzerinden karşılaştırma yapan `Equals` ve `GetHashCode()` otomatik olarak tanımlanacaktır.  Sealed olarak işaretlenmediyse bu methodlar ezilebilir. 

Kendi türünü alan copy constructor’a sahiptir. Ayrıca parametresiz virtual clone methoduna sahiptir. 

Miras alma vardır. With ifadesi ile var olan nesnenin istenilen propertysinin değeri değişmiş yeni bir nesne elde edilebilir. 

```csharp
public data class Person { string FirstName; string LastName; } 

public data class Student : Person { int ID; } 

Person person = new Student { FirstName = "Scott", LastName = "Hunter", ID = GetNewId() }; 

otherPerson = person with { LastName = "Hanselman" }; 
```
Records tanımlamanın iki yöntemi vardır. 

1.Veri üyeleri olarak belirtme: 
Burada sıralama önemli değildir. Sadece üyeler vardır. 

```csharp
public data class Person { string FirstName; string LastName; } 
 ```
2.Pozisyonel tanımlama 
Burada sıralama önemli olduğu ve belirtildiği için Constructor’ı ve  Deconstruct methodu da otomatik olarak tanımlanmıştır. 

```csharp
public data class Person(string FirstName, string LastName);
var person = new Person("Scott", "Hunter"); // pozisyonel construction 

var (f, l) = person;                        // pozisyonel deconstruction 

 ```

##Hedef Türünde Koşulsal İfade 
c ? e1 : e2 gibi bir koşulsal ifade de e1 ve e2 için ortak bir tür yok ise, veya varsa da ortak türe implicit bir dönüşüm yoksa e1’den T’ye ve ayrıca e2’den T’ye implicit dönüşüm sağlayan implicit ifade tanımlanır. 

##Covariant Return Types
Türetilmiş bir sınıfın bir fonksiyonunu ezerken dönüş değerini daha kısıtlayıcı olabilecek şekilde ezebilmeyi amaçlar. 

```csharp

class Compilation 
{ 
    virtual Compilation WithOptions(Options options)... 
} 

class CSharpCompilation : Compilation 
{ 
    override CSharpCompilation WithOptions(Options options)... 
} 
```
##Extension GetEnumerator 

Foreach döngülerinin extension GetEnumerator methodlarını tanımasını sağlar.

##Module İlklendiriciler 
Dotnet platformunda olsa da C# da olmayan bir özellik. Bir modül ilklendirici assembly ilk yüklendikten sonra ilk çalışan fonksiyondur. Static Constructor’ın class için değil modül (assembly)için uygulanmış hali denebilir. 
```csharp
using System.Runtime.CompilerServices; 

class C 
{ 
    [ModuleInitializer] 
    internal static void M1() 
    { 
        // ... 
    } 
} 
```
 

Attribute kullanılabilmesi için bazı gereklilikler vardır:
1.Kullanılacak method static olmalı. 
2.Parametresiz olmalı. 
3.Void dönüş değerine sahip olmalı 
4.Generic olmamalı ya da generic type içermemeli. 
5.İçerdiği modülden method erişilebilir olmalı.(local fonksyion olmamalı ve internal veya public erişicileri ile işaretlenmiş olmalı) 

##Partial Method Geliştirmeleri 

Partial methodlar için artık açıkça private, public... gibi erişici etiketleri kullanılabiliecek. Eğer erişiciler kullanıldı ise tanım ve belirtim tarafında da aynı şekilde belirtmek gerekecek. 

Partial method üzerindeki diğer kısıtlamalar da ayrıca kaldırılmaktadır.(void olmayan türde dönüş, ref, out parametreleri, extern belirteci...) 

```csharp
partial class D 
{ 
    internal partial bool TryParse(string s, out int i);  
} 
 
partial class D 
{ 
    internal partial bool TryParse(string s, out int i) { } 

} 
```

Ref, out gibi keywordler kullanılırken erişiciler açıkça belirtimelidir. Belirtilmemesi hata nedeni olacaktır. 
 
Partial methodlar override ve interface ile de kullanılabilecektir.
 
```csharp
interface IStudent 
{ 
    string GetName(); 
} 

partial class C : IStudent 
{ 
    public virtual partial string GetName();  
} 

partial class C 
{ 
    public virtual partial string GetName() => "Jarde"; 
} 
```
##Üst-Seviye İfadeler 
Bazı zamanlar sadece yeni bir şey öğrenmeyi denerken ya da var olan bir şeyin nasıl çalışıtığını incelerken çok basit programlar yazarız. Bunları yazarken standart olarak  

```csharp
static class Program 
{ 
    static async Task Main(string[] args) 
    { 
        // ifadeler 
    } 
} 
```
Şeklinde Main’in içinde yazmamız gerekmekte. Artık basit denemeler için direkt olarak ifade yazılarak program derlenip çalıştırılabilecek.

*Örnek olarak:* 
```csharp
using System; 
Console.WriteLine("Test"); 
return 1; 
```