25 Kasım 2020 Çarşamba

C# Erişim Operatörleri ve İfadeleri

      S.A Arkadaşlar,

       Bugünkü yazımızın konusu C# ile erişim operatör ve ifadelerini ele alacağız. Aslına bakıldığında herkesin bildiği bir konu olmasına rağmen özellikle yeni sürümlerin gelmesiyle birlikte bu konularda eksik kaldığımız, kendimizi güncellemediğimiz ifadeler oluyor. Bu yüzden C#'in daha önceki sürümlerinde olan konulara kısaca değinip geçerken sonradan eklenen ya da daha az gördüğümüz operatör ve ifadelere daha fazla odaklanacağız.

       Ele alacağımız konular aşağıdaki gibidir. Burada konu başlıklarını ingilizce olarak vereceğiz, fakat ayrıntılarına girdiğimizde Türkçe olarak çevirmeye çalışacağız. Her ikisinin de bilinmesi açısından böyle bir yöntem izlemeyi uygun buldum.

  • . (Member access expression)
  • () (Invocation expression)
  • [] (Indexer operator)
  • ?. ?[] (Null-conditional operators)
  • ?? ??= (Null coalescing operator) 
  • ^ (Index from end operator)
  • .. (Range operator)
  • :: (Namespace alias qualifier)

     . ifadesi: Sadece C#'ta değil, programlamanın olmazsa olmazlarındandır. C#'ta namespace ve property'ler ayırmakta ve onları çağırmakta kullanılan ifadedir. 

using System.Collections.Generic; // namespace kullanımı
---
var constants = new List<double>(); // static olan olmayan property'lere ulaşmak için
constants.Add(Math.PI);
constants.Add(Math.E);
Console.WriteLine($"{constants.Count} values to show:");
Console.WriteLine(string.Join(", ", constants));

     () ifadesi: Yine sıklıkla kullandığımız başka bir ifade. Method, delegate çağırırken bol bol kullanırız. Ayrıca matematiksel işlemlerde, işlem önceliği olarak kullanırız ve tabii ki cast işlemi yaparken de kullanırız. Bunlarla ilgili örnekleri inceleyelim. 

Action<int> display = s => Console.WriteLine(s); // action oluşturulması
int result = (int)Math.Sqrt((10 + 5 ) * 3); // cast ve işlem önceliği

var numbers = new List<int>();
numbers.Add(result );
numbers.Add(17); //Add methodunun çağrılması display(numbers.Count); //action çağrılması

    [] operatörü: Sıklıkla dizilerde gördüğümüz köşeli parantez operatörünün ayrıca attribute ile de kullanımı mevcuttur. Ayrıca dictionary yapısı ile key value değerleri için de kullanılır. Benzersiz keyler kullanılması gerekmektedir, aksi takdirde birden fazla aynı isimle key olamayacağı hatası fırlatacaktır. Dizilerle kullanıldığında ise gerekli indisi bulamadığında yine hata fırlatacaktır. Aşağıdaki kodları inceleyelim.

double[,] matrix = new double[2,2]; //2.boyutlu bir dizi tanımlanıyor
matrix[0,0] = 1.0;
matrix[0,1] = 2.0;
matrix[1,0] = matrix[1,1] = 3.0;
var determinant = matrix[0,0] * matrix[1,1] - matrix[1,0] * matrix[0,1];
Console.WriteLine(determinant);  // output: -3
----
var dict = new Dictionary<string, double>(); // key string, value double bir dictionary tanımlanıyor
dict["one"] = 1;
dict["pi"] = Math.PI; //tanımlanan keylere değerler atanıyor.
Console.WriteLine(dict["one"] + dict["pi"]);  // output: 4.14159265358979
----
[Required] //burada ise attribute kullanımı vardır. Name alanı zorunlu belirtiliyor.
public string Name{ get; set; }

     ?. ?[] null kontrolü: C# 6 ile gelen çok güzel bir null kontrolüdür. Benim de sıklıkla kullandığım bir kontrol şeklidir. Karmaşık olmayan ifadelerde okunurluğu artırırken, karmaşık ifadelerde ise okunurluğu oldukça zorlaştırabilmektedir. Bu yüzden kullanımı çok dikkatli şekilde yapmakta fayda vardır.  Şimdi aşağıdaki kodları inceleyelim.

int? length = people?.Length; // people null ise ifade null olur.
int? length = (people != null) ? (int?)people.Length : null; //yukarıdaki ifade ile aynı işi yapar.
----
double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
    return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN; //?? ifadesini aşağıda ele alacağız.
}

var sum = SumNumbers(null, 0);
Console.WriteLine(sum); // output: NaN -> setsOfNumbers?[indexOfSetToSum] null olduğu için NaN döner.

   ?? ??= operatörleri: C# 7.3 ile gelen ?? operatörünü yukarıdaki kodda kullandığımız gibi, yine çok kullanışlı ifadelerden birisidir. Null kontrolü yapar, eğer değer null ise ifadenin sağındaki değeri atar. Bununla birlikte C# 8'deki bir değişiklikle birlikte ??= ifadesi ise eşit ifadesinden de anlayacağınız üzere ?? ifadesinden sonra gelen değeri kendisi değişkene atayacaktır. Daha net anlaşılması için aşağıdaki kod ve açıklamalarına göz atalım. 

List<int> numbers = null;
int? a = null;

numbers = numbers ?? new List<int>(); // numbers null ise new List<int>() ifadesi atanır.
----
(numbers ??= new List<int>()).Add(5); // yukarıdaki ifadenin kısaltmış halidir.

Console.WriteLine(string.Join(" ", numbers));  // output: 5

   ^ sondan başlatma operatörü: Yine C# 8 ile birlikte gelen başka güzel bir özelliktir. Dizilerden mi kaynaklıdır bilemem ama diğerleri kadar kullanılmadığı aşikar, bu yüzden bu konuyu ayrıca önemsiyorum. Belki de yazıyı yazmama vesile olan operatördür. Kullanımı çok yaygın olmadığı için birçok yazılımcının gözünden kaçmış olabilir. Bir dizide sondan başlayarak eleman bulmaya yarar. 

int[] xs = new[] { 0, 10, 20, 30, 40 };
int last = xs[^1]; //Sondan başlayarak 1.elemanı alır. 0'dan başlamaz, buna dikkat ediniz.
Console.WriteLine(last);  // output: 40 

  .. aralık operatörü: C# 8' ile birlikte gelen ve dizilerle kullanılan başka bir operatördür. Yukarıdaki ifade ile kullanıldığında daha anlamlı olan bir yapıdır. Genel olarak da birlikte kullanımlarını görmek mümkündür. Bir dizide aralık almaya yarar. Aşağıdaki kodu inceleyelim.

int[] numbers = new[] { 0, 10, 20, 30, 40, 50 };
int[] subset = numbers[1..4]; bu ifadeyi kümelerdeki [) olarak algılarsanız daha iyi olacaktır.
// output: 10 20 30 //Bu ifadeye 4.indis dahil değildir.

int margin = 1;
int[] inner = numbers[margin..^margin]; //1. indisten başlayıp dizinin sonuna kadar gider.
// output: 10 20 30 40 //^ yukarıda da belirttiğimiz gibi sonuncu ifade 1'den başlar.

   :: takma isim operatörü: Çok nadir kullanılan ama hayat kurtarabilen bir adlandırma operatörüdür. Sorgularda kullandığımız "as" gibi de düşünebiliriz. Kullandığımız bir dll var ve bu dll başka bir versiyon ile çakışabilir ve biz ikisini aynı anda kullanmak isteyebiliriz. İşte böyle bir durumda her yerde namespace uzun uzun yazmaktansa bu ifadeyi kullanabiliriz. Aşağıdaki kodu inceleyelim. 

extern alias GridV1; 
using Class1V1 = GridV1::Namespace.Class1;	

     Bu vesileyle bu yazımızın da sonuna geldik. Kullandığımız dilin hakkını vermek dileğiyle.

Hiç yorum yok:

Yorum Gönder