C# 7.2 İle Gelen Yenilikler
Selamlar,
Bu makalede, Visual Studio 2017 version 15.5.1 ile hayatımıza giren C# 7.2 yenilikleri üzerine konuşacağız. Biraz da C# 7.1 ile gelen birkaç özelliği inceleyeceğiz. Öncelikle gelin kurulum üzerine konuşalım. Kurulması gereken Visual Studio 2017 bu makalenin yazıldığı an itibari ile Version: 15.5.1‘dir.
Eğere Tools => Extensions and Updates => Updates => Product Updates’de ilgili güncelleme gözükmüyor ise, Visual Studio Installer kullanmanız gerekmektedir. Bunun için Windows button’una basılıp aşağıdaki gibi “Visual Studio Installer” yazılır. Ve son güncelleme yapılır.
Şimdi sıra geldi Console bir application yaratıp, .Net Framework’ü 7.2’ye çekmeye. Yaratılan Proje sağ tıklanıp =>Properties => Build => Advanced… => Language version: C# 7.2′ ye aşağıdaki gibi getirilir.
static async Task Main() 7.1:
Benim çok uzun süredir beklediğim 7.1 ile gelen, Main() methoduna asenkron desteği sonunda karşımızda :)
Şimdi gelin ilk örneğimize bir console application yaratarak geçelim.
Product.cs: Şöyle bir sınıf oluşturalım.
1 2 3 4 5 6 7 |
public class Product { public int ID { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } |
Şimdi yarattığımız console applicationda, static Main() methodunda, bir servisten asenkron olarak “List<Product>“‘ları çekip ekrana basalım.
Program.cs: Aşağıda görüldüğü gibi : “await client.GetAsync(url)” asenkron methodlar Main() methodu içerisinde çağrılabilmektedir. Heyooooo! Amaç dışarı bir servisten, ne zaman tamamlanacağı belli olmayan bir request’i başlatıp, kullanıcıyı bekletmemektir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; namespace CSharp_7._2_News { class Program { static async Task Main(string[] args) { string url = "http://webapiblog.azurewebsites.net/api/products"; using (HttpClient client = new HttpClient()) { HttpResponseMessage response = await client.GetAsync(url); var model = JsonConvert.DeserializeObject<List<Product>>(response.Content.ReadAsStringAsync().Result); foreach (var product in model) { Console.WriteLine(product.Name + ":" + product.Price); } Console.ReadLine(); } } } } |
Ekran çıktısı aşağıdaki gibidir.
Inferred Tuple Element Names 7.1 :
7.1 ile gelen bir diğer özelliği, gelin hep beraber inceleyelim. Öncelikle bir Console Application yaratalım ve aşağıdaki Tuple paketini Nuget’den projemize ekleyelim.
Aşağıdaki uygulamada amaç, gönderilen bir text içinde, istenen bir harfin nerelerinde geçtiğini bulmaktır. Görüldüğü gibi gönderilen text, bir Char[](Letters) dizisi olarak alınmış ve içinde gezilerek aranan harf(e) bulununca bir List<int>(IndexList)‘e eklenmiştir.
var result = (Letter, IndexList) : Burada oluşturulan Tuple kolonlara, ayrıca bir isim verilmemiştir. 7.1’den önce var result = (Letter : Letter, Indexlist : IndexList) şeklinde bir tanımlamanın yapılması gerekmekte idi. Artık istenen alanlara, “result.IndexList“, “result.Letter” şeklinde, herhangi bir isim tanımlaması yapılmadan aşağıda görüldüğü gibi erişilebilmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public static void GetLetter(char Letter,Char[] Letters) { List<int> IndexList = new List<int>(); for (var i = 0; i < Letters.Length; i++) { if (Letter == Letters[i]) { IndexList.Add(i + 1); } } var result = (Letter, IndexList); foreach (var item in result.IndexList) { Console.WriteLine(item + ":" + result.Letter); } } static void Main(string[] args) { char Search = 'e'; Char[] Letters = "Herkese Benden Çay Şakire Yok".ToCharArray(); GetLetter(Search, Letters); Console.ReadLine(); } |
Ekran Çıktısı:
Makalenin devamında, gelin hep beraber 7.2 ile karşımıza çıkan yenilikleri inceleyelim.
In parameters 7.2:
Methodlara gönderilen değişkenlerin readonly olması istenir ise “in” tanımlaması ile bu işlem kolaylıkla yapılabilir. Örneğin aşağıda “AddTax()” şeklinde “local function” tanımlanmıştır. İçinde geçen tax ve price readonly ve değiştirilemezdir. Ürünün fiyatı ve vergisi daima sabittir düşüncesi ile method içinde değiştirilmelerine izin verilmemektedir. Ayrıca out decimal result yine method içinde tanımlanmıştır.
- Eğer AddTax() methodunda “tax=19″ veya “price=25” şeklinde bir atama yapılmaya çalışılsa idi, aşağıdaki hata alınacak idi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
static async Task Main(string[] args) { string url = "http://webapiblog.azurewebsites.net/api/products"; using (HttpClient client = new HttpClient()) { HttpResponseMessage response = await client.GetAsync(url); var model = JsonConvert.DeserializeObject<List<Product>>(response.Content.ReadAsStringAsync().Result); foreach (var product in model) { decimal tax = 18; AddTax(tax, product.Price, out decimal result); Console.WriteLine(product.Name + ":" + result); } Console.ReadLine(); } void AddTax(in decimal tax, in decimal price, out decimal result) { result = price+(price * tax)/100; } } |
Örnek 2:
Yeni bir console application oluşturulur. Amaç 3 lokasyon arasından, 1 tanesine en yakın olanını bulmaktır. Ve bu esnada, yerlerin konumlarının değiştirilmesine “in” yani readonly tanımı ile izin verilmemektedir. Aşağıdaki örnekte Ev’in işe mi yoksa okula mı daha yakın olduğu iç içe extensin yönetimi ile çok temiz (clean code) ile bulunmaktadır :)
- Referanslardan System.Drawing eklenir.
- Yukarıda anlatıldığı gibi, proje sağ tıklanıp, çalıştığı framework 7.2’ye çekilir.
a-) Gelin aşağıdaki gibi Place adında bir struct yaratalım. Yani konumu ve ismi tanımlanacak yer:
1 2 3 4 5 |
private struct Place { public Point Position; public string Name; } |
b) Şimdi gelin Point tipine “Distance()” Extension’ını ekleyelim. Amaç 2 Point arasında mesafeyi bulmaktır. Point’ı yukarıda görüldüğü gibi, yerin yani Place’in konumunun tanımlanması için kullanılmıştır.
1 2 3 4 |
private static double Distance(in this Point p1, in Point p2) { return Math.Sqrt(Math.Pow((p2.X - p1.X), 2) + Math.Pow((p2.Y - p1.Y), 2)); } |
c) Sıra geldi bir Place tipine “Distance()” extension’ı eklemeye. Burada amaç 2 Place yani yer arasında, mesafayı bulmaktır.
1 2 3 4 |
private static double Distance(in this Place p1, in Place p2) { return p1.Position.Distance(p2.Position); } |
d) Bir yere, 2 yer arasından en yakın olanını bulmaya yarıyan “Nearest()” methodu, aşağıdaki gibi tanımlanmıştır. Gördüğünüz gibi aslında ne kadar uzun olan kod, extensionlar sayesinde çok sade bir hale gelmiştir:) Clean Code :)
1 2 3 4 5 6 7 8 9 10 11 |
private static Place Nearest(in this Place p0, in Place p1, in Place p2) { if(p0.Distance(p1) < p0.Distance(p2)) { return p1; } else { return p2; } } |
Main(): Aşağıda 3 yerleşim yeri Place tanımlanmıştır. Ev, Okul ve İş. Eve, okulun mu yoksa işin mi daha yakın olduğu sorusuna cevap aranmaktadır. Var olan Yerlerin konumları, readonly (in) olarak ilgili Methoda gönderilmiştir. Çünkü konumlar sabittir. Ve değiştirilmemesi gerekmektedir. Ev’in Nearest() methoduna “Okul” ve “Ofis” yerleri gönderilerek, en yakın olan yerin adı ekrana basılmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
static void Main(string[] args) { Place Scholl; Place Home; Place Office; Scholl.Position = new Point(x: 20, y: 40); Scholl.Name = "Yıldız Teknik Üni."; Home.Position = new Point(x: 60, y: 80); Home.Name = "Fenerbahçe"; Office.Position = new Point(x: 30, y: 40); Office.Name = "Mecidiyeköy"; Console.Write($@"Eve En Yakın Olanı: {Home.Nearest(Scholl, Office).Name}"); Console.ReadLine(); } |
Ekran Çıktısı:
private protected 7.2:
Bir method ya da property için tanımlanan bu erişim belirliyici, protected ile kendisinden türüyen ve private ile aynı assembly yani namespacede olan sınıftan erişilebilecektir.
Aşağıdaki örnekte: Product sınıfının Price property’si private protected tanımlanmıştır.
- FinalProduct : Product’dan türediği için Price protected erişim belirleyicisini sağlamakta ve “FormatPrice()” methodunda “product.Price”‘a erişilebilmektedir.
- FinalProduct ve Product aynı “CSharp_7._2_News” assembly yani namespace altında oldukları için, Price private erişim belirleyicisini sağlamıştır. Bu neden ile “FormatPrice()” methodunda “product.Price”‘a erişilebilmektedir. Aşağıdaki kodda herşey yolundadır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace PrivateProtected { class Program: FinalProduct { static void Main(string[] args) { FinalProduct product = new FinalProduct(); WriteLine(product.FormatPrice()); ReadLine(); } } public class Product { public int ID { get; set; } public string Name { get; set; } public string Category { get; set; } private protected decimal Price { get; set; } } class FinalProduct :Product { public string FormatPrice() { FinalProduct product = new FinalProduct() { Category = "Mobile", Name = "Iphone X", Price = 6890, ID = 1 }; return "Özel ürün Fiyatı:" + String.Format("{0:#,##0.000}", product.Price) + "TL"; } } } |
Örnek Hata 1:
Hata 1-) Eğer: Main() Methodunda, ayni namespace altındaki Product sınıfına ait Price aşağıdaki bir kullanım ile erişilmek istenir ise, yukarıdaki gibi bir hata alınır. Çünkü protected erişim sınırlıyıcı ile Main methodu Product’dan türetilmemiştir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Program { static void Main(string[] args) { Product product = new Product(); Console.WriteLine(product.Price); Console.ReadLine(); } } class FinalProduct { public string FormatPrice() { Product product = new Product() { Category = "Mobile", Name = "Iphone X", Price = 6890, ID = 1 }; return "Özel ürün Fiyatı:" + String.Format("{0:#,##0.000}", product.Price) + "TL"; } } public class Product { public int ID { get; set; } public string Name { get; set; } public string Category { get; set; } private protected decimal Price { get; set; } } |
Çözüm: İlgili sınıf, Inherit edilince sorun aşağıdaki gibi çözülür.
1 2 3 4 5 6 7 8 9 |
class Program : Product { static void Main(string[] args) { Program product = new Program() { Category = "Food", Name = "Meet Ball", Price = 30, ID = 2 }; WriteLine(product.Price); ReadLine(); } } |
Hata 2-) : İlgili base sınıftan Inherit olmuş ama başka bir assembly’de bulunan sınıf, aşağıdaki gibi “product.Price” propertysine erişemez. Erişim hatası verir. Çözüm, ilgili sınıfı aynı assembly’e koymaktır.
1 2 3 4 5 6 7 8 9 10 11 |
namespace OtherAssembly { class OtherProduct : Product { void Print() { OtherProduct product = new OtherProduct(); WriteLine(product.Price); } } } |
Non-Trailing named arguments 7.2:
C# 7.2’de istenir ise bir method çağrılır iken, parametrelerine isimleri ile beraber değer atanarak tetiklenebileceği gibi, bazı parametrelerine isimleri olmadan da doğrudan değer verilebilir. Örneğin aşağıda “Add()” methoduna ait “y” parametresi isme göre değer atanmış iken, sırasına göre x ve z parametrelerine isimsiz olarak değer atanmıştır. Aynı işlem, 7.1 ve daha düşük versiyonlarda aşağıda görülen hatayı verirken, C# 7.2’de hiçbir sorun ile karşılaşılmadan derlenmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Program { static void Main(string[] args) { Program p = new Program(); int result=p.Add(y:50,x:20,z:12); int result2 = p.Add(50, y: 20, 12); Console.ReadLine(); } private int Add(int x, int y, int z) { return x + y + z; } } |
Hata mesajı: 7.1’de bu hata mesajı alınır. 7.2’de ve üzerinde bu hata mesajı alınmaz.
Hex ve binary sayısal değerlerde “_” artık geçerli 7.2:
C# 7.2 versiyonundan önceki sürümlerde, aşağıdaki gibi hex ve binary değerlerde “_” yani alt çizgi kullanıldığında, yukarıdaki gibi bir hata alınmaktadır. Ama bu sorun artık 7.2 ile kalkmıştır. “_” günümüzde daha çok, bir çeşit format gibi okunaklılığı arttırmak için haneler arası ayraç olarak kullanılmaktadır.
1 |
int binaryValue = 0b_0101_0101; |
Geldik bir makalenin daha sonuna. Bu makalede C# 7.2 ve biraz da 7.1 ile hayatımıza giren yenilikleri hep beraber inceledik.
Yeni bir makalede görüşmek üzere hoşçakalın. Esen kalın.
Kaynaklar : https://blogs.msdn.microsoft.com/mazhou/
Hocam emeğinize sağlık. Teşekkürler.
Ben teşekkür ederim.
Bora hocam ben yazılım ögreniyorum C# Yazılımcı olmak istiyorum liseyi acıktan okuyorum acık ögretim gidiyorum sansım varmı hocam ?
Selamlar;
Tabi ki var. Neden olmasın. Yeterki çalış ve yılma …
Hoşçakal.
Bora.
hocam cok sagol senin sayende ögüt aldım ve gunde kac saat calısmam lazım ve yazılım icin sadece c# mı yoksa baska programlmaı gerekiyormu
Selam,
Bu işin saati yok:) Bazen 12 saat bazen 1 saat. Sen belirleyecen. Ama başlarda çok uzun sürebiliyor :) Başka dil dersen ilgi alanına göre değişir. Big Data dersen Python, embeded dersen C++, algoritmalar Go ile fena değil. Mobile iPhone dersen swift. Böyle gider.
İyi çalışmalar.
ve bora hocam yazılım kodlama vb seyler ögrendikten sonra iş nasıl bulabilirim ?
Ve bildiğini kanıtlayarak :) Makale yaz. Github’a adam gibi repo kodlar at. Son olarak paraya takılmadan kendini geliştirebileceğin bir iş bul. Görüşmede bu işe ne kadar hevesli olduğunu, şirkete nasıl değer katabileceğini ve çalışkanlık ile sabırın göbek adın olduğunu söyle :)
Çok Sagolun Hocam <3
İncelemeniz için teşekkürler yararlı bilgiler ve acıklayıcı olmuş yazılarınızın devamını bekliyoruz
Teşekkürler. Elimden geleni yapıcam.