C# 7.0 Yenilikleri

Daha C# 6.0 'ın tüm özelliklerini yeni yeni kavramışken Microsoft C# 7.0 ile gelecek olan özelliklerden bazılarını açıkladı bile. Gelecek olan feature'lara baktığımızda çokta fazla major yenilikler yok gibi ancak yine de kayda değer şeyler var. Gelin bu feauture'ları ufaktan bi inceleyelim Öncelikle C#7.0 ın özellikleri VS2015'de default olarak yok. Normalde vs2015'de yeni bir proje açtığınızda default C# 6.0 ile gelir. 7.0'ın özelliklerini aktifleştirmek için VS de proje oluştururken ufak bir kaç şey yapmak gerekiyor. İlk olarak C#da bir tane console proje oluşturalım ve sonrasında solution'da bulunan projeye sağ tıklayıp özellikler diyelim. Açılan ekrandan Build tabına geçelim ve "conditional compilation symbols" textbox'ına __DEMO__ yazalım. Projeyi build ettikten sonra artık C# 7.0 özelliklerini otomatik olarak alacaktır.     C# 7.0 Features Local functions Binary literals Digit separators Pattern matching Ref returns and locals   Local functions Bir çok yazılım dili fonksiyon içinde fonksiyon yazımına izin verirken C# için bu geçerli değildi. 7.0 ile artık fonksiyon içerisine fonksiyon tanımlıyor olacağız. public int Method_1(int x,int y) { int Metho_2(int x) { return x*x; } return Metho_2(x)*y; }   Binary literals and Digit separators Bu özelliğin aslında 6.0 ile geleceği söyleniyordu ancak galiba yetiştiremediler ki 7.0 ile geliyor. Bu özellikle birlikte artık numeric tanımlamaları binary olarak yazabileceğiz.  public void BinaryLiterals() { var numbers = new[] { 0b0, 0b1, 0b10 }; foreach (var number in numbers) { Console.WriteLine(number); } }   Daha büyük sayıları daha kolay okuyabilmek için ise "_" ayıracını kullanarak digitleri gruplayabiliriz ve bu decimal, hexa veya binary'ler içinde geçerlidir.  int oneBillion = 1_000_000_000; int num_1 = 0x7FFF_1234; int num_2 = 0b1001_0110_1010_0101;   Pattern matching Pattern matching özelliği fonkysionel programlama dillerinde çok yaygın bir özellik ve C# 7.0 da "is" operatörü ile bazı özellikleri bize sunuyor ancak final sürümü ile birlikte daha fazla özellik ekleneceği söyleniyor. 1) Type Pattern Type pattern reference typle'ların runtime type test işlemi yaparken işimize yarayacak olan bir özellik. public void Foo(object item) { if (item is string s) { WriteLine(s.Length); } } 2) Constant Pattern Constant pattern bir ifadenin runtime değerini test etmek için kullanılır. public void Foo(object item) { switch (item) { case 10: WriteLine("It's ten"); break; default: WriteLine("It's something else"); break; } } 3) Var Pattern public void Foo(object item) { if(item is var x) { WriteLine(item == x); // prints true } } 4) Wildcard Pattern public void Foo(object item) { if(item is *) { WriteLine("Hi there"); //will be executed } } 5) Recursive Pattern public int Sum(LinkedListNode<int> root) { switch (root) { case null: return 0; case LinkedListNode<int> { Value is var head, Next is var tail }: return head + Sum(tail); case *: return 0; } }   Ref returns and locals C# ın ilk versiyonundan itibaren "ref" keyword'ünü kullanarak metotlara pass by reference ile parametreler geçebiliyoruz. Bu özellikle birlikte metottan pass by reference ile değer dönmesini sağlıyor. static void Main() { var arr = new[] { 1, 2, 3, 4 }; ref int item = ref Get(arr, 1); Console.WriteLine(item); //2 item = 10; Console.WriteLine(arr[1]); //10 Console.ReadLine(); } ref int Get(int[] array, int index) { return ref array[index]; }   Kısaca C# 7.0 ile gelecek olan feature'lara değindik ancak relase olması için henüz çok erken ve ilerleyen sürümlerde üstte belirttiğimiz özelliklerinin bazıları değişebilir de. 7.0 ile ilgili yeni duyumlar geldikçe de yazmaya devam...  

Web Config Custom Section

WebConfig Asp.Net tabanlı projelerde istemci tarafında ilk çalıştırılan XML tabanlı bir sayfadır diyebiliriz. İçerisinde bir çok bilgi barındırır ve bir istemci yani kullanıcı websitenize erişmeye çallıştığında ilk webconfig çalışır ve içerisinde set edilen bilgilere göre projenizi çalıştırır & ayağa kaldırır. Nedir bu bilgile diye soracak olursa;  Debug, Release mode ayarı, .Net Framework bilgisi, Varsa Database conn string bilgisi, Kullanılan .Net Kütüphanelerinin versiyon bilgileri, Uygulama Debug modda nasıl Release modda nasıl çalışacak bunun bilgisi, Site içi ve dışı yönlendirme ayarları vs. Görüldüğü üzre uygulama ile ilgili bir çok ayar mevcut kısacası uygulamanın configurasyonu ile ilgili sayısızca özellik & ayar set edilebilir. Bunun gibi ayarların dışında web.config içerisinde uygulama içi kullanılan çeşitli özel bilgiler & ayarlar da saklayabilir. Peki neden bu bilgileri burda saklıyoruz veya turuyoruz ?? Uygulamada Constant diye herhangi bir class oluşturup bunun içerisinde de tutabiliriz. Ama bu sefer ne olur derseniz. Orda tuttuğunuz bilgiyi değiştirmek için tekrardan projeyi açıp class içerisinde set edilen değeri değiştirip uygulamayı tekrardan ilgili yere deploy etmemiz gerekmekte. İşte aslında WeConfig bizi bu durumdan kurtarıyor. Webconfig dosyası deploy edildiği yerde projede ki tanımlı olduğu haliyle XML formatında tutuluyor yani uygulama içinde tanımlı olan class gibi dll'e çevrilip içini tekrardan açamayacağımız bir türde durum değil. Bu nedenle değişme olasılığı yüksek olan bilgileri WebConfig içerisinde tutup ihtiyaç duyulduğunda deploy edildiği dosyada ki folder e giderek çok rahat bir şekilde içini açıp ilgili ayarı değiştirebiliriz. Örnek olarak; uygulama kullanılan iletişim sayfasında ki email adresi veya uygulamaın herhangi bir yerinde kullanılan ve sonradan değiştirmeye açık olan bir text/metin.  <?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> <compilation defaultLanguage="c#" debug="true" /> </system.web> <appSettings> <add key="ContanctEmailAddress" value="info@canertosuner.com" /> </appSettings> </configuration> Yukarıda da görüldüğü gibi uygulama içerisinde yönetmek istediğimiz değerleri <appSettings> içerisinde unique bir key vererek value alanlarına değerleri set edebiliriz. Bu değeri code tarafından okumak istediğimizde de bilindiği üzre şu şekilde yapıyoruz; string emailAddress= ConfigurationSettings.AppSettings["ContactEmailAddress"]; Peki ya kendimiz aynı <appSettings> section'ı olduğu gibi bir custom secton yapmak istersek.. Case şu şekilde olsun. Kredi faizi hesaplayan bir uygulamamız var ve bu uygulamadaki faiz oranlarını webconfig den okuyup hesaplıyor. Aslında bu gibi bilgiler direkt olarak DB den de alınabilir ama bizim rojemizde webConfig den alalım.  1.Adım WebConfigde section tanımı yapma <configuration> <configSections> <section name="KrediFaizleri" type="MyProject.KrediFaizleriSection" /> </configSections> </configuration> Yukarıda da görültüğü gibi KrediFaizleri adında bir section ımızın olacağı bilgisini verdik.   2.Adım Section ve içerisindeki elementleri yazma </configSections>  tag'inin altında aşağıdaki gibi kodumuzu yazalım <KrediFaizleri> <Krediler> <add tip="ihtiyac" oran="1.65"/> <add tip="tasit" oran="1.96"/> <add tip="konut" oran="1.20"/> </Krediler> </KrediFaizleri> Burda Krediler diye bir array var ve içerisinde Kredi objesi olduğunu düşünelim. Bu obje içerisinde de tip ve oran adında 2 tane string property var. Aslında yukarıda ki xml kodunun tam karşılığı bu. Yukarıda 3 adet kredi için oran bilgisi girdik şimdi sırada bu değerleri webconfigden okumamızı sağlayacak C# kodlarını yazmaya geldi   3.Adım KrediFaizleri elementini tanımlama Yukarıda Krediler arrayinin içerisinde Kredi objesi olduğunu söylemiştik.Aslında bu bir element. Biz adına KrediFaizleriElement diyelim ve classımız aşağıdaki gibi olacaktır. public class KrediFaizleriElement : ConfigurationElement { [ConfigurationProperty("tip", IsKey = true, IsRequired = true)] public string KrediTipi { get { return (string)this["tip"]; } set { this["tip"] = value; } } [ConfigurationProperty("oran", IsKey = true, IsRequired = true)] public string Oran { get { return (string)this["oran"]; } set { this["oran"] = value; } } }   4.Adım KrediFaizleri array'ini tanımlama Bu adımda webconfig de ki array'i almamızı sağlayan ConfigurationElementCollection den türeyen bir class yazıyoruz. Bu class'ı kullanarak tanımladığımız section içerisinde ki collection'ı içerisindeki Element ler ile birlikte alıyoruz. [ConfigurationCollection(typeof(KrediFaizleriElement))] public class KrediFaizleriCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new KrediFaizleriElement(); } protected override object GetElementKey(ConfigurationElement element) { return ((KrediFaizleriElement)element).KrediTipi; } }    5.Adım KrediFaizleriSection class ını oluşturma Fark ettiyseniz  en içten en dışa doğru ilerliyoruz. İlk olarak Element sonra Collection şimdide sırada Section var. Aşağıda yazılan KrediFaizleriSection webconfigde tanımladığımız KrediFaizleri tag'ini okumamızı sağlayacak olan class. İçerisinde Faizler array i var ve bu array'in içerisindede KrediFaizleriElement objeleri bulunacak. public class KrediFaizleriSection: ConfigurationSection { [ConfigurationProperty("KrediFaizleri", IsDefaultCollection = true)] public KrediFaizleriCollection Faizler { get { return (KrediFaizleriCollection )this["KrediFaizleri"]; } set { this["KrediFaizleri"] = value; } } }     Son Adım Webconfig de tanımlı değerleri okuma ve filtreleme işlemi. Bu adıma kadar şu sırayla lerledik; WebConfig de Section tanımlama, WebConfig de Section içerisindeki Collection ve Elementleri tanımlama, C# tarafında Element&Model class'ını oluşturma, C# tarafında Collection class'ını oluşturma, C# tarafında Section class'ını oluşturma, Şimdi ise sırada bu class ları kullanarak WebConfig de tanımlı değerleri okuma işlemi var. Bunun için aşağıdaki class ı kullanabiliriz.  public static KrediFaizleriElement KrediOranınıGetir(string krediTipi) { //KrediFaizleri section'nını içerisindeki elementler ile birlikte aldık var element= ConfigurationManager.GetSection("KrediFaizleriSection") as KrediFaizleriSection; //Paramaetre olarak verilen kredi tipine göre linq sorgusu yaptık var returnValue = element.Faizler.Cast<KrediFaizleriElement>().SingleOrDefault(c => c.KrediTipi== krediTipi); //İlgili kredi WebConfigde varmı kontrol ettik if (returnValue == null) throw new InvalidOperationException(string.Format("Kredi Tipi {0} bulunamadı !", krediTipi)); //Bulunan krediyi geri döndürdük return returnValue; } İşlemlerimiz bu kadar. KrediOranınıGetir metodunu gerekli yerde çağrısını yaparak kullanabiliriz.

yield nedir nasıl kullanılır

Bilineceği üzere bir class ın foreach iterasyonuna sahip olabilmesi için IEnumerable interfacesini implement etmesi gerekmekte. IEnumerable 'ı implemente eden class bu implementle birlikte override edilmesi gereken GetEnumerator metoduna sahip olur ve bu metodun içerisini doldurduktan sonra artik bu class da foreach ile gezebilecek duruma gelir. GetEnumerator metodunu override ederken, MoveNext(), Reset() metotlarini ve Current isimli propertyleri ile ilgili logic'i handle etmemiz gerekiyordu. İşte yield sayesinde bunları yapmaktan kurtuluyoruz.  Mantigi oldukca basit ama bazi projelerde uygulamaya entegrasyonu sıkıntı çıkarabiliyor. Iste bu  sıkıntıları gidermek için C# 2.0 ile birlikte gelen yield keywordu sayesinde bu işlemlerin tumu bizim için arka planda yapilmis olacak. Senaryomuz şu şekilde olsun; geriye db de kayıtlı olan ürünleri dönen bir metodumuz var ve bu metodu yield kullanmadan ve yield kullanarak yazmaya çalışalım. Yield kullanmadan public static IEnumerable<Product> GetAllProducts() { using (var db = new DbEntity()) { var productList = from product in db.Product select product; return productList.ToList(); } }   Bu normal şartlarda kullandığımız yöntem. İlgile metodu aşağıdaki gibi çağırıp dönen listeye direk olarak erişebilirsiniz. var productList = GetAllProducts(); yield kullanarak ise şu şekilde yazabiliriz  Yield Kullanarak public static IEnumerable<Product> GetAllProducts() { using (var db = new DbEntity()) { var productList = from product in db.Product select product; foreach (var item in productList) { yield return product; } } } yield da ise şu şekilde çalışır; döngüye her girdiğinde yield return product satırında fonksiyonun çağrıldığı yere ilgili product item'ını döner yani return'ü gördü diye foreach den ve metoddan direkt çıkmaz ve listenin içindeki tüm elemanlar bitinceye kadar bu işlemi yapmaya devam eder. IL Disassambler(ILDASM) acarak code tarafında MoveNext,Reset ve Current gibi uyeler yazmamamiza ragmen yield keywordu sayesinde arka planda bunlarin yazildigini goruyoruz.  Bir diğer örnek olarak ise şunu verebiliriz;  public void Consumer() { foreach(int i in Integers()) { Console.WriteLine(i.ToString()); } } public IEnumerable<int> Integers() { yield return 1; yield return 2; yield return 4; yield return 8; yield return 16; yield return 45; } Foreach de dönerken her bir int i için IEnumerable<int> Integers() metoduna giderek değerleri bize teker teker döndürebiliyor.

C# Indexer Nedir

Indexer özel tanımlı bir property'dir ve sadece class içerisinde tanımlanabilir. Tanımlandığı class'a indexlenebilir özelliği kazandırır. Array işlemlerinde kullandığımız [ ] operatörünü tanımlamış olduğumuz bir bir class'ı diziymiş gibi işlemler yapabilmek içinde kullanabiliriz. Örneğin Department diye bir class olsun ve departman isimlerini önce ayrı bir array içerisinde sonrada indexer yardımıyla class içerisinde tutalım. Önce çalışan isimlerini ayrı bir List array'de kullanmak istediğimizde nasıl yazıyoruz ona bakalım. public static void Main() { var arr = new List<string>(); arr[0]="Bilgi İşlem"; arr[1]="Proje Yönetimi"; arr[2]="Analiz"; arr[3]="İş Geliştirme"; arr[4]="Destek Sistemler"; } Yukarıda da olduğu gibi gayet basit bir şekilde bir List tanımlayıp departman isimlerini bu List'in içine attık.   Indexer kullanarak bunu nasıl yapardık birde ona bakalım, public static void Main() { Department dprt = new Department(); dprt[0]="Bilgi İşlem"; dprt[1]="Proje Yönetimi"; dprt[2]="Analiz"; dprt[3]="İş Geliştirme"; dprt[4]="Destek Sistemler"; Console.WriteLine(dprt[4]); //Destek Sistemler } public class Department { public string Name { get; set; } public int ID { get; set; } //indexer tanımlaması private string []names = new string[5]; public string this [int index] { get { return names[index]; } set { names[index] = value; } } } Yukarıda da görüldüğü üzre Department class'ımıza indexer kullanarak indexlenebilir özelliği kazandırdık ve [ ] kullanarak tıpkı array kullanıyormuş gibi değer atama ve değer okuma işlemlerini yapabildik Görüldüğü gibi bir class içerisinde property tanımlar gibi indexer tanımlayabiliyoruz. Düşünüldüğünde çok gerek duyulan bir özellik değil gibi duruyor çünkü genelde başka şekilde ihtiyacımızı görüyoruz ama ama örnek olarak Ado.net ile uğraşan arkadaşlar SqlDataReader class'ını bilirler database'den den belli bir column'da bulunan değeri okumak için aşağıdaki gibi dr["Name"] yazarak o değere ulaşmamızı sağlar bunu yapabilmemizin sebebi SqlDataReader class'ı içerisinde indexer tanımlandığından dolayı [ ] diyerek get işlemi yapabildik SqlDataReader dr = cmd.ExecuteReader(); ArrayList names= new ArrayList(); while (dr.Read()) { names.Add(dr["Name"]); //SqlDataReader class'ı içerisinde indexer tanımlandığından dolayı [ ] diyerek get işlemi yapabildik }  

C# Extension Method Kullanımı

Kelime anlamı genişletilebilir metod olan Extension Method'lar C#3.0 ile hayatımıza girmiştir ve yaptığı iş itibatiyle kullanım açısından son derece faydalı metodlardır. Tek cümleyle özetlemek gerekirse class ve struct yapılarını modify etmeden ilgili struct yada class'için extension metodlar eklememizi sağlar.  Extesion metod yazarken uymamız gereken bir kaç kural vardır. Bunlar; Extension metodlar static bir class içerisinde static olarak tanımlanmalıdır.  Extend edilecek class ilgili extension metoda metodun ilk parametresi olarak verilip önünde this keyword'ü ile tanımlanmalıdır Extension metod da tanımlı parametrelerden sadece 1 tanesi this keyword'ü ile tanımlanır Hemen bir örnek üzerinde inceleyelim. Case'imiz şu olsun; Bir tane extension metodumuz var ve bu metod integer bir değer alıp asal mı değil mi diye kontrol etsin. public static class MyExtensions { public static bool IsPrime(this int integer) { //tembellik edip implementation'ı yazmakla uğraşmadım :) return true; } } Yazdığımız metodu aşağıdaki görselde olduğu gibi kullanmak istediğimizde int tanımlı değişkenin adı"." nokta dediğimizde extensionMetod'u intellisense de görebileceğiz.  class Program { static void Main(string[] args) { int anyNumber = 123456; if(anyNumber.IsPrime()) { //asal sayı } else { //asal sayı değil } } } Heralde en güzel yanı da bu olsa gerek metodu extension tanımladığımız için sanki o metod int struct'ına içerisinde tanımlı bir metodmuş gibi direkt olarak "." nokta deyip kullanabiliyoruz.  Yukarıda ki örnekte int tipini baz alarak ilerledim ancak ihtiyaç dahilinde bütün tipler ve kendi tanımladığımız objeler içinde extension metodlar yazabiliriz. Yine örnek olarak ; bir Person class'ımız ver ve içerisinde DateTime tipinde ismi BirthDate olan bir property olsun. Bir tane GetBirthDate adında extension metod tanımlayalım ve bu metod bize parametre olarak aldığı Person objesinde bulunan BirthDate alanını return ettirsin. public class Person { public string FullName {get;set;} public DateTime BirthDate {get;set;} } public static class MyExtensions { public static DateTime GetBirthDate(this Person prs) { return prs.BirthDate; } }   Şimdi bu metodu kullanan kısmı yazalım using System; class Program { static void Main(string[] args) { Person prs=new Person(); DateTime bDAte = prs.GetBirthDate(); } } Görüldüğü gibi Extension metod kullanım alanımızı ihtiyaca göre genişletip metodlarımızı istediğimiz yerde "." nokta diyerek fıtı fıtı çağırıyoruz :)