C# – Func(Önceden Tanımlanmış Delege Türü)
Önceki yazılarımdan C# Delegate(Temsilci) ve Event(Olay) Kullanımı başlıklı makalemizde ayrıntılı bir biçimde delegelerden bahsetmiştim.Delege, metodların adreslerini yani metodları fiziksel olarak işaretleyebilen yapılar olduğunu hatırlayalım.Tanımladığımız delegenin yapısına göre işaretleyeceği metodlar değişiklik gösterebiliyordu.Buradan yola çıkarak, ihtiyacımız olan delegeyi belirli bir yapı sayesinde daha pratik tanımlayıp daha sonra o delegeye uygun bir metod atamamızı “Func<T,TResult>” tipi sayesinde gerçekleştiriyoruz ve bu işleme “Önceden Tanımlanmış Delege” diyoruz.Bu makalemizde bu işlemin nasıl yapıldığını ve Func delegesini detaylı bir biçimde inceleyeceğiz.
Öncelikle Func<T,TResult> tipini birazdaha detaylı bir biçimde irdeleyelim.
Func tipi, bir veya birden fazla(16 haneye kadar) parametre alabilen ve geriye T tipinde değer döndüren bir delege yapısıdır.Bu delege sayesinde, alacağı parametreler ve geriye döndüreceği değeri simgeleyen delegemizi tanımlayabilir ve o tanımladığımız yapıdaki herhangi bir metodu bu delegeye işaretletebiliriz.Eğer bir işlemde delegeye ihtiyacınız varsa, Func ile hızlı ve pratik bir şekilde ihtiyacınızı giderebilir ve delegeyle uğraşmanıza gerek kalmayabilir.
Peki Func<T,TResult> ile nasıl delege tanımlanıyor? diye sorarsanız eğer aşağıdaki kodu inceleyiniz.
Func<string,string,bool>
Yukarıdaki tanımı incelersek eğer, “string” tipte iki parametre alan ve geriye “bool” tipinde değer döndüren bir delege tanımlanmış oluyor.Yukarıda da bahsettiğim gibi Func tipinde 16 haneye kadar parametre tanımlayabiliyoruz.Haliyle bu tanımlanan tiplerden hangisinin parametre hangisinin geri dönüş değeri olduğunu nerden anlıyoruz diye sorarsanız eğer, n tane tip tanımladıysak, n+1 inci tip geri dönüş tipi olarak kabul edilmektedir.Aşağıdaki ekran görüntülerini incelersek olayı daha iyi anlamlandırmış olabiliriz.


Yukarıdaki ekran görüntülerini incelerseniz eğer, sonuncu parametreye kadar tanımlanan tipler delegenin parametre tiplerini, sonuncu parametre ise delegenin geri döneceği değerin tipini taşımaktadır.
Şimdi bir kaç örneklendirme yapalım.
İki adet “string” tipten parametre alan ve geriye “int” dönen Func yapısını oluşturalım.
Func<string,string,int>
Bir adet “int”, bir adet “float” ve iki adet “bool” tipinden parametre alan ve geriye “object” tipten veri dönen Func yapısını oluşturalım.
Func<int,float,bool,bool,object>
Evet, buraya kadar Func tipinin nasıl tanımlandığını mantıksal açıdan izah etmiş olduk.Şimdide delegelerde olduğu gibi tanımladığımız bir Func tipine, tanımlanan yapıdaki bir metodu nasıl işaretleteceğimizi inceleyelim.
static void Main(string[] args)
{
Func<int, int> Toplam = ToplamMetodu;
Console.Write(Toplam(5));
Console.Read();
}
static int ToplamMetodu(int sayi)
{
int Toplam = 0;
for (int i = 0; i <= sayi; i++)
{
Toplam += i;
}
return Toplam;
}
Yukarıdaki kod bloğunu incelerseniz eğer, “int” tipinde parametre alan ve geriye “int” tipinde değer döndüren delegemizi Func tipi sayesinde “Toplam” isminde tanımlamışız.Haliyle bu delege tanımına uyan “ToplamMetodu” isminde bir metod tanımlayıp bunu “Toplam” isimli önceden tanımlanmış delegemize işaretletmişiz.Gördüğünüz gibi artık metodumuzu bir delegeyle istediğimiz şekilde yönetebiliyoruz.
Önceki yazılarımdan Lambda İfadeleri (Lambda Expressions) başlılkı yazımda Lambda ifadelerinden bahsetmiştik.Hatırlarsanız eğer bu ifadeleri kullandığımız alanlar Func ile başlayan parametrelerdi.Func tipinin bir delege olduğunu ve delegelerin metodları işaretlediğini düşünürsek eğer, Lambda ifadelerinin bir metod tanımlayıcısı olduğu çıkarımını yapabiliriz.
Şimdi yukarıdaki örneği Lambda ifadesi ile yapmaya çalışalım.Burada yapacağımız olay, tanımlanmış Func tipine uygun metodu yazıp işaretleteceğimize, o metodu Lambda ifadeleriyle delegemize anlamlandıracağız.
static void Main(string[] args)
{
Func<int, int> Toplam = sayi =>
{
int ToplamDeger = 0;
for (int i = 0; i <= sayi; i++)
{
ToplamDeger += i;
}
return ToplamDeger;
};
Console.Write(Toplam(5));
Console.Read();
}
Yukarıdaki kod bloğunu incelerseniz eğer, Func tipine “=” operatöründen sonra “sayi” isminde bir değişken tanımlamış olduk.Bu değişken “int” tipindeki parametrenin değerini taşımaktadır.”=>” operatörü ile Scope”{ }”(Süslü parantezler) açarak geriye “int” tipinde değer döndüren prosedürel kodlarımızı yerleştirdik.Gördüğünüz gibi Lambda ifadeleriyle önceden tanımlanmış delegemizin tipine uygun bir metod tasarlamış olduk.Bu işlemde .NET’in pratik yanlarından birisini göstermektedir.. 🙂
Lambda ifadeleriyle ilgili bu örnek tatmin etmeyeceğinden dolayı bir örnek daha yapalım.
static void Main(string[] args)
{
int Deger = Convert.ToInt32(Console.ReadLine());
Func<bool> SinyalVarmi = () =>
{
if (Deger == 1)
{
return true;
}
else
{
return false;
}
};
Console.Write(SinyalVarmi());
Console.ReadLine();
}
Yukarıdaki kod bloğunu incelerseniz eğer, dışarıdan alınan “int” tipindeki değer eğer 1 ise “True”, 1 den farklı ise “False” döndürecek bir algoritma bulunmaktadır.Önceden tanımlanmış delegemiz hiç parametre almamaktadır, lakin geriye “bool” tipinde değer döndürmektedir.Delegemiz parametre almayacağından dolayı, parantez aç kapa”()” yaparak metodumuzun parametre almayacağını belirtiyoruz.Scope’lar içerisine geriye “bool” tipinde değer döndürecek kodlarımızı yazıyoruz.
Şimdide konumuzu Lambda ifadelerini genellikle kullandığımız Extension metodlarımızla bağdaştıralım.LINQ ya da Entity Framework’de çoğunlukla kullandığımız Where Extension metodunu inceleyelim.
![]()
Yukardaki Where metodunu incelersek eğer,”int” tipinden bir koleksiyonda kullanıldığından dolayı, parametresinde “int” tipinde parametre alan ve geriye “bool” tipinde değer döndüren bir metod almaktadır.Haliyle bu metod Func tipinde ve yukarıdaki şartlara uygun bir delegeye işaretlenecektir.Genellikle biz herhangi bir koleksiyonda Where Extension metodunu kullanıyorsak aşağıdaki gibi Lambda ifadeleriyle metodumuzu tanımlarız.
static void Main(string[] args)
{
List<int> Sayilar = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
List<int> GelenSayilar = Sayilar.Where(sayi => sayi == 1).ToList();
foreach (var item in GelenSayilar)
{
Console.Write(item);
}
Console.ReadLine();
}
Lakin yukarıdaki gibi Lambda ifadesi kullanılmadan aşağıdaki gibi metod tanımlanarakta delegeye işaretlendirilebilir.
static void Main(string[] args)
{
List<int> Sayilar = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
List<int> GelenSayilar = Sayilar.Where(SayilariGetir).ToList();
foreach (var item in GelenSayilar)
{
Console.Write(item);
}
Console.ReadLine();
}
static bool SayilariGetir(int Sayi)
{
return Sayi == 2;
}
Burada sizlere ters mantık olarak olayı anlatmaya çalıştım.
Son olarak Func tipinin nerelerde kolaylık sağladığından bahsederek makalemize son vermek istiyorum.
LINQ ve Entity Framework mimarilerinde ya da Extension metodlarda bu kolaylıklardan farkında olmasakta yoğun bir şekilde faydalanmaktayız.Koleksiyon içerisinde veri taraması gibi işlemleri Func yapısı sayesinde daha rahat gerçekleştirebiliyoruz.
Pratik bir yapıya sahip olan bu tip profesyonel ve esnek yapılardaki mimarilere çok iyi ayak uydurabilmekte ve hızlıca çalışma olanağı sunmaktadır.
Sonraki makalemizde görüşmek ümidiyle..
İyi çalışmalar..
