C# 12 İle Gelmesi Muhtemel Özellikler
Selamlar,
Bu makalede, C# 12 ile gelmesi beklenen bazı özellikleri hep beraber inceleyeceğiz.
1-)Primary Constructors:
Aşağıda görüldüğü gibi, “RedisPersonKeyGenerator” sınıfının Constructor’ı yoktur. Class, parametreleri sanki bir method gibi alınmıştır. Böylece içeride ayrıca bir değişken tanımlanmasına gerek kalmamıştır. Aslında bu özellik, record tipler için çoktan sağlanmıştır. RedisCore sınıfı, “RedisPersonKeyGenerator” sınıfından türemiştir. Doğal olarak RedisCore sınıfı, “RedisKey” propertysine doğrudan erişebilmektedir. RedisCore sınıfının kendi içinde constructor’ı bulunmaktadır. Eski usül ile yeni usülün farkını göstermek için bu şekilde bir örnek yazılmıştır. RedisCore sınıfı içinde Local Redise, 30 dakka expirelı parametre olarak gelen obje atanmaktadır. Key olarak base’den gelen RedisKey kullanılmaktadır.
Simdi bir sınıftan Constructor ve ayrıca parametre tanımlama ihtiyacını kaldırmak kodu kısaltıp, kod okunaklığını arttırabilir ama set ve get işlemlerinde araya girip müdahele etmeyi ortadan kaldırır. Bu da Observer gibi Notify yapan Design Patternler için pek de istenen bir durum değildir. Ayrıca bence, bir sınıftaki property’e erişmek, değişkene doğrudan erişmekten çok daha sağlıklıdır :)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class RedisPersonKeyGenerator (int id, string name) { string RedisKey => $"person:{id.ToString()}:{name}"; } public class RedisCore(int id, string name, object val, int expireMinute): RedisPersonKeyGenerator(id,name) { public RedisCore() : this(78, "bora", null, 30) {} // default RedisCore public int Id => id; public object Value => val; public TimeSpan ExpireTime = TimeSpan.FromMinutes(expireMinute); public bool SetValue(){ using(RedisEndpoint conf = new RedisEndpoint { Host = "127.0.0.1", Port = 6379 }) using(RedisClient redisClient = new RedisClient(conf)) { redisClient.Set(RedisKey, Value, ExpireTime); } return true; } } |
2-) *Semi-auto-properties (field keyword’ü):
Benim bu seneki favori yeniliğim açık ara budur. Aşağıdaki örnekde, bir sınıfın standart property özellikleri kullanılmıştır ve üçgenin alanı bulunmuştur. Peki ya var olan bir sınıfa değişken tanımlamadan property atayabilsek.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; public class Program { public static void Main() { Triangle triangle=new(); triangle.Height=5; triangle.BaseLength=10; Console.WriteLine(triangle.FindArea()); } public class Triangle { private int _height {get; set;} private int _baseLength {get; set;} public int Height {get{ return _height;} set{_height = value;}} public int BaseLength {get{ return _baseLength;} set{_baseLength = value;}} public double FindArea(){ return (_height*_baseLength)/2; } } } |
C# 12 Ile Son Durum: Aşağıda görüldüğü gibi “Height” ve “BaseLength” propertyleri değişkenler olmadan ” field” keyword’ü ile atama ve değer alma işlemleri yapılmıştır. Buradaki “field” keyword’ü, Backward compatibility için büyük bir tehlikedir. Çünkü, ilgili sınıf içinde önceden field adında bir değişken tanımlanmış olabilir. Ve bu da önceden yazımış kodda, bir çakışmaya sebebiyet verebilir. Peki çözüm için ne yapabiliriz ? Mesela “field” yerine “this.field” keyword’ünü kullanabiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System; public class Program { public static void Main() { Triangle triangle=new(); triangle.Height=5; triangle.BaseLength=10; Console.WriteLine(triangle.FindArea()); } public class Triangle { public int Height {get{ return field;} set{ field = value;}} public int BaseLength {get{ return field;} set{field = value;}} public double FindArea(){ return (Height * BaseLength)/2; } } } |
Şimdi gelin Auto Property kısmına bakalım: En başta, ilk yaratılma anında ilgili fieldlar, default olarak aşağıdaki gibi atanabilirler.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class AutoTriangle { private int Height => field ?? = GetHeight(); public int BaseLength field ?? = GetBase(); public static int GetHeight(){ Random random = new Random(); return random.Next(5); } public static int GetBase(){ Random random = new Random(); return random.Next(10); } } |
3-) Lambda Expression’da Yapılan Geliştirmeler:
C# 12’de parametreler için varsayılan değerlerin tanımlamasına izin verilerek, lambda ifadelerin güçlenmesi sağlanmıştır. Örneğin, aşağıdaki durumda price atanmadığında default olarak 100 kabul edilmekte ve son fiyat 1.18 ile çarpılarak geri dönülmektedir. Eğer price atanmış ise, o zaman atanan price doğrudan 1.18 ile çarpılarak geri dönülür. Ayrıca artık lamda functionlarda, çok daha complex expressionlar yazılabilecektir. Bence ilerde bu lambda ifadeler, aynı Linq querylerde olduğu gibi “tail” olarak uç uca eklenen karmaşık sorguları basitleştiren bir tool haline gelebilirler.
1 2 3 |
var finalPrice = (int price = 100) => price * 1.18; finalPrice(); // 118 finalPrice(50); // 59 |
4-) Switch Expression’da Yapılan Geliştirmeler:
Klasik Yöntem: Aşağıda görüldüğü gibi sınav scoruna göre, başarı durumu raporlanmaktadır.
1 2 3 4 5 6 7 |
var result = score switch { int i when i >= 90 => "Pekiyi", int i when i >= 70 => "iyi", int i when i >= 50 => "Orta", _ => "Zayıf" }; |
C# 12 Switch : Artık yeni yapıda, switch yapısında ayrıca yeni bir değişkene ihtiyac duyulmamaktadır. Ben zaten hiçbir zaman bu extra değişken ihtiyacına, anlam verememiştim :)
1 2 3 4 5 6 7 |
var result = score switch { >= 90 => "Pekiyi", >= 70 => "iyi", >= 50 => "Orta", _ => "Zayıf" }; |
5-) Tip Tanımlamada Alias Kullanma:
Artık istenir ise, hemen hemen her türe alias yani takma isim, aşağıda görüldüğü gibi verilebilecektir. Örneğin GoogleMapPoint => (string) isim ve (double) kordinat bilgisi almaktadır. Bu tip SetCordinate() methodunda tanımlanmıştır.
Ayrıca tanımlı alias’da ilgili değişkenlere daha kolay erişim icin => “GoogleDetailMapPoint” alias’ı, aşağıdaki gibi tanımlanmıştır. İlgili string değişkene “Name” ve double değişkene “Point” adları ile erişilebilir. Tek istisna olarak nullable referance tiplerin alias veremessiniz. Türlere takma ad vermek, kullandığınız gerçek türleri soyutlamanıza ve kafa karıştırıcı veya uzun genel adlara kolay adlar vermenize olanak sağlar. Bu da, kodunuzu okumayı kolaylaştırır.
1 2 3 4 5 6 7 |
using GoogleMapPoint = (string, double); using GoogleDetailMapPoint = (string Name, double Point); public class Program { public bool SetCordinate(GoogleMapPoint cordinate){} } |
Geldik bir makalenin daha sonuna. Bu makalede, C# 12 ile gelmesi muhtemel bazı başlıca özelliklere göz attık. C# Lead Designer’ı Mads Torgersen, değişime ve C#’a yeni özelliklerin katılmasına devam edeceklerini, ekibi ve kendisinin önümüzdeki dönemlerde de “Değişimin“, esas mottoları olduğunu belirtti. Bütün bunların yandan artık daha fazla değişim istemeyen, C#’ın yeterince complex bir hal aldığını düşünen bir kitle de bulunmaktadır. Bu kitle, bir işi yapmanın birden çok yolunun olmasının, kod okunaklığını ve kod standardını sağlamanın zorlaştırdığını idda etmektedirler.
Torgersen ve ekibi, bir yandan bu tepkilere dikkat ederken, diğer yandan da bizim hayatımızı kolaylaştıracak bir dizi muhteşem özellikleri tasarlıyıp geliştirmek gibi zorlu bir iş yükü altında bulunmaktadırlar. Ben geçen ayki MVP Summit’de yüz yüze, C#’a getirdikleri bu efsane yenilikler için özellikle teşekkür ettim. Dile yaptıkları bu eklentiler ile aslında birçok yeni design pattern’e de zemin hazırlamış oluyorlar. Aslında bunun da gayet bilincindeler.Asıl amaçları basitlik ve kod okunabilirliğini arttırmak yani Clean Code.
Yeni bir makalede görüşmek üzere hepinize hoşçakalın.
merhaba sevgili üstad çalışmalarınızın devamını dilerin bir ömür boyu kodlamalar ..
Tesekkur ederim Hocam :)