Değerli
Okurlarım Merhabalar,
Bildiğiniz gibi temsilciler (delegates)
çalışma zamanında metodların başlangıç adreslerini işaret eden
tiplerdir. Bu tipleri uygulamalarımızda tanımlarken çalışma zamanında
işaret edebilecekleri metodların geri dönüş tipi ve parametrik
yapılarını bildirecek şekilde oluştururuz. Ancak özellikle , C# 1.1
ortamında temsilcilerin kullanımında parametre ve dönüş tipileri
açısından iki önemli sıkıntımız vardır. Bu sıkıntıların kaynağında
birbirlerinden türeyen yani aralarında kalıtımsal (inheritance)
ilişkiler olan tipler yer alır.
Nitekim temsilciler C# 1.1 versiyonunda
oluşturulacakları zaman, işaret edecekleri metodlar için kesin dönüş ve
parametre tipi uyumluluğunu ararlar. Dolayısıla bu tiplerde kalıtımsal
ilişkiler söz konusu olduğunda ortaya çıkan iki temel problem vardır. Bu
iki temel sorunumuza bakmadan önce, konunun odağında aralarında kalıtım
ilişkisi olan iki sınıf olduğunu göz önüne almalıyız. Örneğin Sekil ve
Dortgen isimli iki sınıfımız olduğunu ve Dortgen sınıfının Sekil
sınıfından türediğini varsayalım. Bu sınıfların sahip olduğu içeriğin
bizim için şu aşamada çok fazla önemi yoktur. İlk olarak covariance'
lığa neden olan sorunu ele alalım. Aşağıdaki uygulamamızı dikkatle
inceleyelim.
using System;
namespace UsingCovariance
{
public class Sekil
{
public Sekil()
{
}
}
public class Dortgen:Sekil
{
public Dortgen()
{
}
}
public delegate Sekil Temsilci();
class Class1
{
public static Sekil Metod_1()
{
return null;
}
public static Dortgen
Metod_2()
{
return null;
}
[STAThread]
static void Main(string[] args)
{
Temsilci
temsilci=new Temsilci(Metod_1);
temsilci=new Temsilci(Metod_2); // Derleme zamanı hatası
}
}
} |
Bu uygulamayı derlediğimizde,
| temsilci=new
Temsilci(Metod_2); |
satırı için Method
'UsingCovariance.Class1.Metod_2()' does not match delegate
'UsingCovariance.Sekil UsingCovariance.Temsilci()' hatasını
alırız. Peki burada sorun nedir? Temsilci isimli delegate tipimiz, Sekil
sınıfından nesne örneklerini geriye döndüren ve parametre almayan
metodları işaret edebilecek şekilde tanımlanmıştır . Bu durumda,
| Temsilci temsilci=new
Temsilci(Metod_1); |
satırı düzgün olarak çalışacaktır. Nitekim
Metod_1 delegate tipimizin tanımlamalarına uyan tarzda bir metoddur.
Oysaki Metod_2 metodumuzun geriye döndürdüğü değer Dortgen sınıfı
tipindendir. Dolayısıyla temsilci nesnemizin tanımladığı bildirimin
dışında bir dönüş tipininin dönüşü söz konusudur. Hatırlayın,
temsilciler işaret edecekleri metodlar için kesin dönüş tipi ve
parametre tipi uyumluluğu ararlar. Oysaki Dortgen ve Sekil sınıfı
arasında kalıtımsal bir ilişki söz konusudur ve bu sebeple bu tarz bir
kullanımın sorunsuz olarak çalışacağı düşünülmektedir. Çünkü kalıtımın
doğası gereği bu Dortgen sınıfına ait nesne örnekleri Sekil sınıfına ait
nesne örneklerine dönüştürülebilir. Ancak temsilcimiz açısından bu kural
ne yazık ki geçerli değildir. Yani temsilcimiz belirtilen tipler için
çalışma zamanında çok biçimliliği destekleyememiştir.
Peki bu sorunu nasıl çözebiliriz? Tek
yapabileceğimiz Dortgen sınıfına ait nesne örneklerini döndüren Metod_2
isimli metodumuzu işaret edecek yeni bir delegate nesnesini aşağıdaki
örnek kod parçasında olduğu gibi tanımlamak ve kullanmak olacaktır. Bu
tahmin edeceğiniz gibi hantal bir çözümdür. Bir birleri arasında tür
dönüşümü yapılabilecek iki sınıf için gereksiz yere iki ayrı temsilci
tipi tanımlamak zorunda kalışımız dahi istenmeyen bir durumdur.
public delegate Sekil
Temsilci();
public delegate Dortgen Temsilci2();
class Class1
{
public static Sekil Metod_1()
{
return null;
}
public static Dortgen Metod_2()
{
return null;
}
[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new
Temsilci(Metod_1);
Temsilci2 temsilci2i=new
Temsilci2(Metod_2);
}
} |
İşte C# 2.0' da, delegate tipi için söz
konusu olan bu sorun ortadan kaldırılmıştır. Yukarıdaki örneğimizin
aynısını C# 2.0' da yazdığımızı düşünürsek her hangi bir derleme zamanı
hatası almayız. Covariance' ın desteklenebilmesi için C# 2.0' a
getirilen ekstra bir kodlama tekniği yoktur.

Bu tamamen .net çekirdeğinde delegate tipi
üzerinde yapılan bir düzenlemenin sonucudur.
 |
Covariance,
temsilcilerin çalışma zamanında işaret etmek istediği
metodların, aralarında kalıtımsal ilişki olan dönüş tipleri
arasındaki poliformik uyum sorununu ortadan kaldıran bir özellik
olarak nitelendirilebilir. |
Temsilci nesnelerimizin işaret edeceği
metodların dönüş tiplerinin kalıtımsal ilişkilere izin verecek şekilde
düzenlenmiş olması elbetteki çalışma zamanında bize büyük bir esneklik
getirmektedir. Nitekim bu sayede birbirlerinden türemiş n sayıda sınıfa
ait nesne örneklerinin dönüş tipi olarak kullanıldığı metodları tek bir
delegate nesnesi vasıtasıyla çalışma zamanında işaret edebiliriz.
Gelelim contravariance durumuna. Bu kez
kalıtım ilişkisine sahip olan sınıf örnekleri, temsilcilerin işaret
edeceği metodların parametrik yapıları içerisinde kullanılmaktadır.
Aşağıdaki örnek kod parçası C# 1.1 için bu durumu örneklemektedir.
using System;
namespace UsingContravariance
{
public class Sekil
{
public Sekil()
{
}
}
public class Dortgen:Sekil
{
public Dortgen()
{
}
}
public delegate int Temsilci(Dortgen dortgen);
class Class1
{
public static int Metod_1(Dortgen
dortgen)
{
return 0;
}
public static int Metod_2(Sekil
sekil)
{
return 0;
}
[STAThread]
static void Main(string[] args)
{
Temsilci
temsilci=new Temsilci(Metod_1);
temsilci=new Temsilci(Metod_2); // Derleme zamanı hatası
}
}
} |
Bu kez delegate tipimiz geriye int
tipinden değer döndüren ve parametre olarak Dortgen sınıfı tipinden
nesne örneklerini alan metodları işaret edebilecek şekilde
tanımlanmıştır. Kodu derlediğimizde Method
'UsingContravariance.Class1. Metod_2(UsingContravariance.Sekil)' does
not match delegate 'int UsingContravariance.Temsilci(UsingContravariance
.Dortgen)' hatasını alırız. Yine delegate tipimiz burada parametrik
imza uyuşmazlığından bahsetmektedir. Sorun,
| temsilci=new
Temsilci(Metod_2); |
satırında oluşur. Çünkü Metod_2 Dortgen
sınıfı tipinden bir nesne örneğini parametre olarak almaktansa Dortgen
sınıfının üst sınıfı olan Sekil sınıfından bir nesne örneğini parametre
olarak almaktadır. Buradaki problem tersi durum içinde söz konusudur.
Yani temsilcimizi tanımlarken metodun alacağı parametrenin, türeyen
sınıf yerine temel sınıftan (base class) bir nesne örneğini kullanacak
şekilde aşağıdaki kod parçasında görüldüğü gibi tanımlandığını
düşünürsek;
public delegate int
Temsilci(Sekil sekil);
class Class1
{
public static int Metod_1(Dortgen dortgen)
{
return 0;
}
public static int Metod_2(Sekil sekil)
{
return 0;
}
[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new
Temsilci(Metod_1); // Derleme zamanı hatası
temsilci=new Temsilci(Metod_2);
}
} |
bu sefer Metod_1 için oluşturulan temsilci
isimli nesnemiz üzerinden aynı hata mesajını alırız. Doğal olarak, metod
parametlerinin üst sınıftan veya türeyen sınıftan olması durumu
değiştirmeyecektir.
 |
Contravariance,
temsilcilerin çalışma zamanında işaret etmek istediği metodların
parametreleri arasında kalıtımsal ilişkiye sahip tiplerin neden
olduğu polimorfik uyum sorununu ortadan kaldıran bir özellik
olarak nitelendirilebilir. |
Parametrelerin uyumsuzluğunun neden olduğu
bu sorunu C# 1.1 ile çözmek için, covariance tekniğinde olduğu gibi her
bir metod için ayrı temsilci nesnelerini aşağıdaki kod parçasında olduğu
gibi tanımlamamız gerekecektir.
public delegate int
Temsilci(Sekil sekil);
public delegate int Temsilci2(Dortgen dortgen);
class Class1
{
public static int Metod_1(Sekil sekil)
{
return 0;
}
public static int Metod_2(Dortgen Dortgen)
{
return 0;
}
[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new
Temsilci(Metod_1);
Temsilci2 temsilci2=new
Temsilci2(Metod_2);
}
} |
Yukarıdaki örneğimizi C# 2.0 ile
derlediğimizde ise her hangi bir sorun olmadığını görürüz.

Parametrelerin arasındaki kalıtımsal
ilişki, çalışma zamanında temsilciler oluşturulurken de
değerlendirilecek ve nesneler arasındaki tür dönüşümü başarılı bir
şekilde parametrelerede yansıyacaktır. Bu covarince probleminde olduğu
gibi bize yine büyük bir esneklik sağlar. Aralarında kalıtımsal ilişki
olan n sayıda sınıf nesne örneğini kullanan metodları tek bir temsilci
nesnesi ile çalışma zamanında işaret edebilme yeteneği. Böylece geldik
bir makalemizin daha sonuna, bir sonraki makalemizde görüşünceye dek
hepinize mutlu günler dilerim.
Burak Selim ŞENYURT
selim@bsenyurt.com