Csharp 9 ve sonrası
Can Alpay Çiftçi
Posted on September 6, 2020
Bu yazım daha önce hazırlanmış bu blogda 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
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
// Ö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
(_, _) => 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
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 alınmıştır.
Fonksiyon pointerlarının eklenmesi
Artık Csharpta da unsafe kod olarak fonksiyon pointerları kullanılabilecek.
Örnek olarak
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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...)
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.
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
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:
using System;
Console.WriteLine("Test");
return 1;
Posted on September 6, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.