Generic Kısıtlamaları
C# ta generic-tip parametrelerinin yerine hangi kısıtlamalarda client-tanımlı parametrelerin kullanılacağını derleyiciye belirtmek zorundasınızy. Üç tip kısıtlama vardır. Türeme kısıtlaması derleyiciye generic-tip parametrenin hangi temel tipte class veya interface den türemesi gerektiğini belirtir. Varsayılan yapıcı (default constructor) kısıtlaması derleyiciye generic-tip parametresinin default public contructor a (parametresiz public constructor) sahip olduğunu gösterir. Referans/Değer tip kısıtlayıcısı generic tip parametrenin referans mı yoksa değer tipindemi olduğunu sınırlar. Bir generic tip birden fazla kısıtlayıcı barındırabilir.
Şunu da belirtmek lazım ki bu kısıtlayıcılar opsiyoneldir, ama generic-tip parametreler kullanırken bunları kullanmak mecburi gibidir. Bunları kullanmadığınız sürece object-tip parametrelerde olduğu gibi daha fazla tip-güvenlik kontrolleri yapmanız gerekir.Kısıtlamalar generic-tip metadatanın önemli bir parçasıdır, bu sayede client-side derleyiciside bunun avantajlarından faydalanabilir. Client-side derleyicisi client geliştiricisine kısıtlamalara uymasını zorlayarak tip-güvenliği sağlar.
Kısıtlamaların kullanım ihtiyacına yönelik bir örnek verecek olursak: Bağlı listeye indexleme kabiliyeti ve bir key e göre arama kazandırmak isteyelim
public class LinkedList{ T Find(K key) {...} public T this[K key] { get{return Find(key);} } }
Bu clienta aşağıdaki kodu yazmasına olanak sağlar.
LinkedListlist = new LinkedList (); list.AddHead(123,"AAA"); list.AddHead(456,"BBB"); string item = list[456]; Debug.Assert(item == "BBB");
Arama yapabilmek için tüm listeyi taramak, her bir node un key ini aranan key ile karşılaştırmak ve eşleşen node u geri döndürmek gerekir. Problem şu ki aşağıdaki method derlenmez:
T Find(K key)
{
Node current = m_Head;
while(current.NextNode != null)
{
if(current.Key == key) //Derlenmez...
break;
else
current = current.NextNode;
}
return current.Item;
}
Neden derlenmediğinin sebebi:
if(current.Key == key)
Yukardaki satır derlenmez çünkü derleyici K nin == operatörünü destekleyip desteklemediğini bilemez. Mesela structlar bu çeşit bir gerçekleştirmeyi desteklemez. Bu == operatör kısıtlamasını aşmak için IComparable arayüzünü kullanabilirsiniz:
public interface IComparable
{
int CompareTo(object obj);
}
CompareTo() methodu eşitlik durumunda 0 döndürür, böylece Find() methodu bunu aşağıdaki gibi kullanabilir:
if(current.Key.CompareTo(key) == 0)
Malesef bu kodda derlenmez çünkü derleyici K nın IComparable dan türeyip türemediğini bilme imkanı yoktur.
Siz bunu IComparable a cast edip kullanabilirsiniz ama bu da tip-güvenliği için pahalıya mal olur:
if(((IComparable)(current.Key)).CompareTo(key) == 0)
Türeme Kısıtlaması
C# 2.0 da kısıtlama tanımlamak için where keyword ünü kullanırız. where keyword ünü derleyiciye parametrenin neden türemesi gerektiğini belirtmek için kullanırız.
public class LinkedListwhere K : IComparable { T Find(K key) { Node current = m_Head; while(current.NextNode != null) { if(current.Key.CompareTo(key) == 0) break; else current = current.NextNode; } return current.Item; } //Rest of the implementation }
Derleyici burada list in key argümanı için IComparable dan türeme şartı koşucak ve kodu eğer key bundan türemiyorsa derlemiyecektir.
Kısıtlama size IComparable ı kullanmanıza izin verse bile, key olarak değer tipinde, mesela integer tipinde bir değişken kullandığınızda tekrar boxing yapmanız gerekecek. Bu sorunu aşmak için IComparable kullanmanız gerekecek:
public interface IComparable{ int CompareTo(T other); bool Equals(T other); }
Key için kullanımı aşağıdaki gibidir.
public class LinkedListwhere K : IComparable {...}
Kısıtlamalar gerçek türemelerden sonra yazılmalıdır. Mesela LinkedList IEnumerable interface inden türüyorsa where bundan hemen sonra yer almalıdır:
public class LinkedList: IEnumerable where K : IComparable {...}
Aynı generic tip parametresinde birden fazla interface kısıtlaması getirebilirsiniz Mesela:
public class LinkedListwhere K : IComparable ,IConvertible {...}
Her bir generic tip parametre için kısıtlama yazılabilir, mesela:
public class LinkedListwhere K : IComparable where T : ICloneable {...}
Generic tip parametreler için class dan türeme kısıtlamasıda getirebilirsiniz. Ama sadece bir tane belirleyebilirsiniz:
public class MyBaseClass
{...}
public class LinkedList where K : MyBaseClass
{...} C# kısıtlama olarak başka bir generic tip parametre kullanmanızada olanak sağlar:
public class MyClasswhere T : U {...}
Constructor Kısıtlaması
Generic sınıfın içinde bir generic nesne oluşturmak istediğinizi düşünün. C# derleyicisi clientın kullanacağı tip argümanın tipinde argümanlara sahip bir constructor olup olmadığını bilemez, böylece derleme yapamaz.
Bu problemi aşmak için C# size public default contructor tanımlamanıza olanak tanır. Bu new()kısıtlaması kullanarak yapılır. Örneğin:
class Nodewhere T : new() { public K Key; public T Item; public Node NextNode; public Node() { Key = default(K); Item = new T(); NextNode = null; } }
Türeme kısıtlaması ile birlikte kullanımı aşağıdaki gibidir:
public class LinkedListwhere K : IComparable ,new() {...}
Referans/Değer Tip Kısıtlaması
Generic tip parametresinin değer tipindemi yoksa başka tiptemi olacağını aşağıdaki gibi kısıtlayabilirsiniz:
public class MyClasswhere T : struct {...}
Aynı şekilde referans tipinde olduğunuda class keywordü ile kısıtlayabilirsiniz:
public class MyClasswhere T : class {...}
Hiç yorum yok:
Yorum Gönder