Coder Bilişim Akademisi uzaktan eğitimlerinde öğrencilerime delegate konusu için çalışmalarını istedim. Bir sonraki derste çalışmalarını sorduğumda internetteki kaynakların ya çok temel seviyede (özellikle Türkçe kaynaklarda) ya da çok ileri seviyede olduğunu söylediler. Biz dersimizde delegate konusunu temelden başlayarak güzelce işledik ve tüm öğrenciler konuyu anladılar. Bunun üzerine delegate (temsilci) konusuna, ne çok basit, ne de çok karmaşık olmayan bir senaryo ile aynen derste anlattığım gibi bloğumda da yer vermek istedim.

Sorularınızı ve geri bildirimlerinizi yazının altına yorum yaparak bildirin. Böylece daha anlaşılır yazılar ile karşınızda olacağım.

Delegate C# programlama dilinde oldukça önemli bir role sahiptir. (örn. Linq lambda ifadeleri).  Bu yüzden onları gerçekten iyi anlamamız önemli. Haydi vakit kaybetmeden başlayalım.

Öncelikle delegate nedir ?

Delegate Türkçe karşılığı ile temsilci bazı nesne tabanlı programlama dillerince (örn. C#) kabul görmüşken, bazılarınca (örn. java) OOP yaklaşımına aykırı olduğu düşünülerek kabul görmemektedir. Aslına bakarsanız nesne tabanlı programlama dillerinin atası olan C++ da da delegate yapısı bulunmaktadır. (Bilenler bilir metotlara pointer lar ile erişmek). Kısaca delegate metotlarımızın pointer adreslerini tutan referans türünde bir tiptir.

Basitçe Delegate

Hızlı bir özet ile delegate referans türünde bir tiptir. Aynı class gibi. Kullanım amacı metotlarımızın pointer adreslerini tutmaktır. Ne işime yarayacak dediğinizi tahmin ediyorum cevabı geliyor. Ama önce bir delegate kullanmak için 3 basit adımı bilmek gerekir.

  1. Delegate i tanımlamak
  2. Örneğini oluşturmak
  3. Invoke etmek (uyandırmak ya da çalıştırmak ne derseniz artık)

1 – Senaryo :

Pazarlama departmanımızın işi bütçelerine göre yeni kampanyalar düzenlemek. Pazarlama departmanımızı MarketingDepartment sınıfı ile projemizde tanımlıyoruz. Kampanya oluşturması işini ise MartketingDepartment sınıfının ExecuteNewCampaing metodu üstleniyor. Pazarlama departmanımıza hizmet veren 3 farklı sağlayıcımız var. bunlar; AddressProvider sınıfı ile tanımlanan sağlayıcı beklentimiz olan müşteri adreslerini (Müşteri adresleri CustomerAddress sınıfı temsil eder) GetAddressesNewProspects metodu ile liste olarak sunuyor. CoffeCupCompany ve BallPenCompany sınıfları ile tanımlanan diğer iki sağlayıcımız SendCoffeCup ve SendBallPens metotları ile hizmet vermekte. Bu metotlar müşteri adreslerini liste olarak alıp geriye bool tipinde değer dönüyor.

2 – Delegate kullanmadan nasıl geliştirirdik?

CSharp delegate olmadan UML

CSharp delegate olmadan UML


class Program
{
static void Main(string[] args)
{
bool success = false;

MarketingDepartment MyDepartment = new MarketingDepartment();

success = MyDepartment.ExecuteNewCampaign(5000);

Console.WriteLine("Yeni pazarlama kampanyası {0} sonuçlandı!",
success == true ? "başarılı" : "başarısız");
}
}
public class MarketingDepartment
{
     public bool ExecuteNewCampaign(decimal budget)
     {
          bool success = false;

          AddressProvider MyAddressProvider = new AddressProvider();          

          List<CustomerAddress> ListOfAddresses = 
			MyAddressProvider.GetAddressesNewProspects();

          if (budget < 10000)
          {
              BallpenCompany MyBallpenCompany = new BallpenCompany();
              success = MyBallpenCompany.SendBallPens(ListOfAddresses);
          }
          else
          {
               CoffeeCupCompany MyCoffeeCupCompany = new CoffeeCupCompany();
               success = MyCoffeeCupCompany.SendCoffeeCups(ListOfAddresses);
          }

          return success;
     }
}
public class CustomerAddress
 {
 public string City { get; set; }
 //Müşteri adresleri için gerekli özellikler (Cadde, sokak, mahalle vb.)
 }
public class AddressProvider
{
    public List<CustomerAddress> GetAddressesNewProspects()
    {
        List<CustomerAddress> ListOfAddresses = new List<CustomerAddress>();

 
        return ListOfAddresses;
    } 
public List<CustomerAddress> GetAddressesNewProspects()
{
return new List<CustomerAddress>
{
new CustomerAddress{City="Antalya"},
new CustomerAddress{City="İstanbul"},
new CustomerAddress{City="İzmir"},
new CustomerAddress{City="Ankara"}

};
} 
}

public class BallpenCompany 
{
    public bool SendBallPens(List<CustomerAddress> ListOfAddresses)
    {
        //Her bir müşteriye tükenmez kalem gönderme işlemi

        return true;
    }
}

public class CoffeeCupCompany
{
    public bool SendCoffeeCups(List<CustomerAddress> ListOfAddresses)
    {
          //Her bir müşteriye kahve kupası gönderme işlemi
        return true;
    }
}

3- CSharp delegate kullanarak UML

CSharp delegate kullanarak UML

Pazarlamacılar zeki insanlar, zeki oldukları gibi, işleri hızlandırmak için bir de fikirleri var! “Şöyle dediler bize ; “adresleri AddressProvider’dan geri almak için vakit kaybetmek ve Ballpen Company’ye veya Coffee Cup Company’e göndermek istemiyoruz, bunun yerine, AddressProvider’ın adreslerle ne yapılacağını söyleyelim. Bu bize zaman kazandırır.” Adamlar haklı bize de kodlamak düşer. Hadi kolları sıvıyalım.

Strateji

  1. Çalıştırılacak metotlarımızı sarmalayacak bir delegate tanımlayacağız
  2. MarketingDepartment sarmalayıcı delegate’i kendi tercihine göre dolduracak ve AddressProvider’a gönderecek
  3. AddressProvider delegate’i methoduna parametre olarak alacak ve invoke edecek. Fakat delegate ile invoke ettiği metot ya da metotları bilmeyecek

class Program
{
static void Main(string[] args)
{
bool success = false;

MarketingDepartment MyDepartment = new MarketingDepartment();

success = MyDepartment.ExecuteNewCampaign(5000);

Console.WriteLine("Yeni pazarlama kampanyası {0} sonuçlandı!",
success == true ? "başarılı" : "başarısız");
}
}

public class CustomerAddress
{
public string City { get; set; }
//Müşteri adresleri için gerekli özellikler (Cadde, sokak, mahalle vb.)
}

public class BallpenCompany
{
public bool SendBallPens(List<CustomerAddress> ListOfAddresses)
{
//burada gelen adres listesindeki tüm adreslere tükenmez kalem gönderiyoruz
foreach (CustomerAddress address in ListOfAddresses)
{
Console.WriteLine($"{address.City} adresine tükenmez kalem gönderildi");
}
return true;
}
}

public class CoffeeCupCompany
{
public bool SendCoffeeCups(List<CustomerAddress> ListOfAddresses)
{
// burada gelen adres listesindeki tüm adreslere kahve bardağı gönderiyoruz
foreach (CustomerAddress address in ListOfAddresses)
{
Console.WriteLine($"{address.City} adresine kahve bardağı gönderildi");
}
return true;
}
}

&nbsp;

public class AddressProvider
{
//Burada metodumuzun parametre olarak bir delegate aldığını görüyoruz
public bool HandleCampaign(DoAfterGetAddresses ToDoAfterAddresses)
{
bool success = false;

//Öncelikle adres listesini temin ediyoruz
List<CustomerAddress> ListOfAddresses = GetAddressesNewProspects();

//Şimdi delegate invoke ediliyor (Delegate adım 3)
//Bu işlemde delegate'imize parametre olarak adres listesini vermemiz gerekiyor
success = ToDoAfterAddresses(ListOfAddresses);

/*Bu kodlar ile artık AddressProvider hangi metot tarafından çağırıldığını bilmeyecek
* öyleki hangi metot tarafından çağırıldığı da kendisini ilgilendirmiyor. Hangi metodun
* çağıracağına karar veren MarketinDepartment */

//Ayrıca delegate imzası geriye bool dönüyor. Bende bunu MarketingDepartment a gönderiyorum.

return success;
}
public List<CustomerAddress> GetAddressesNewProspects()
{
return new List<CustomerAddress>
{
new CustomerAddress{City="Antalya"},
new CustomerAddress{City="İstanbul"},
new CustomerAddress{City="İzmir"},
new CustomerAddress{City="Ankara"}

};
}

}