21 Mayıs 2011 Cumartesi

Generic Kullanımı #1

Generic Kullanımı


Generic tipleri sınıflar ve struct lar için kullanabilirsiniz. İşte size faydalı bir generic point (nokta) yapısı:

public struct Point
{
   
   public T X;
   
   public T Y;
}


Generic nokta (point) yapısını integer koordinatlar için kullanabilirsiniz. Örneğin:

Point point;
point.X = 1;
point.Y = 2;


Veya double tipinde koordinatlar için:

Point point;
point.X = 1.2;
point.Y = 3.4;


Şimdiye kadar generic tiplerin temel kullanımını gördük. C# 2.0 ın bazı generice özel syntax yapısıda vardır. Mesela  default() operatörü kullanılan tipin default değerini döndürür. Örneğin stack yapısında listeden pop yapmak istediğimizde kullandımız Pop() methodunu inceleyelim ve stackın boş olduğu durumlarda default bir değer döndermek isteyelim:

public T Pop()
{
   m_StackPointer--;
   if(m_StackPointer >= 0)
   {
      return m_Items[m_StackPointer];
   }
   else
   {
      m_StackPointer = 0;
      return default(T);
   }
}

Referans tipleri için default değer null dır ve value tipleri için default değer 0 dır.

Çoklu Generic Tipleri

Örneğin aşağıdaki gibi bir generic bağlı liste düşünelim:

Kod Blok 3. Generic Bağlı Liste


class Node
{
   public K Key;
   public T Item;
   public Node NextNode;
   public Node()
   {
      Key      = default(K);
      Item     = defualt(T);
      NextNode = null;
   }
   public Node(K key,T item,Node nextNode)
   {
      Key      = key;
      Item     = item;
      NextNode = nextNode;
   }
}

public class LinkedList
{
   Node m_Head;
   public LinkedList()
   {
      m_Head = new Node();
   }
   public void AddHead(K key,T item)
   {
      Node newNode = new Node(key,item,m_Head.NextNode);
      m_Head.NextNode = newNode;
   }
}

Bağlı liste düğümleri (node) depolar:

class Node
{...}


Her bir düğüm bir anahtar (Generic tip parametresi K) ve bir değer tutar (Generic tip parametresi T). Aynı zamanda her bir düğüm bir sonraki düğüme referans verir. Bağlı listeler generic tip parametreleri K ve T ile tanımlanır:

public class LinkedList
{...}


Bu sayede AddHead() gibi generic methodlar ortaya çıkar:

public void AddHead(K key,T item);


Ne zaman generic tipinde bir değişken tanımladığınızda, kullanacağınız tipleri belirlemek zorundasınız. Ama belirlenen tip argümanları kendileride bir generic tip olabilirler. Örneğin, bağlı liste m_Head adında Node tipinde bir değişkene sahip. Bu listedeki ilk elemana referans veriyor. Aynı zamanda generic tipler olan K ve T ile tanımlanmış.


Node m_Head;


Bir düğümün instance ını oluştururken argümanların tipini belirtmelisiniz., bunun içinse bağlı listenin generic tiplerini kullanabilirsiniz:


public void AddHead(K key,T item)
{
   Node newNode = new Node<K,T>(key,item,m_Head.NextNode);
   m_Head.NextNode = newNode;
}

Not olarak söyleyelim liste ile node aynı isimlerde generic tipler kullanıyor. Bu sadece okunabilirliği kolaylaştırma açısından bu şekilde yazılmıştır. Aşağıdaki şekillerdede kullanılabilir:

public class LinkedList
{...}


Veya:

public class LinkedList
{...}


Listenin örnek kullanımı olarak key ler için integer value lar için string kullanmak istersek:


LinkedList list = new LinkedList();
list.AddHead(123,"AAA");


İsteyen başka şekillerdede kullanabilir:


LinkedList list = new LinkedList();
list.AddHead(DateTime.Now,"AAA");   


Bazen alias kullanmak faydalı olabilir.Bu şekilde bir kullanım sizi kod tekrarından kurtarabilir.

Kod Blok 4. Generic tip alias


using List = LinkedList;

class ListClient
{
   static void Main(string[] args)
   {
      List list = new List();
      list.AddHead(123,"AAA");
   }
}

2 Mayıs 2011 Pazartesi

C# Generic Sınıflara Giriş #1

Giriş

Generic sınıflar C# 2.0 'ın en güçlü özelliğidir. Generic sınıflar size type-safe veri yapıları tanımlamanızı sağlar. Bu size  yüksek performans ve kaliteli kod yazmanızı sağlar. Çünkü yazdığınız kodu başka tip verilere uygun olarak tekrardan yazmadan kullanabilmenizi sağlar. Konsept olarak C++ taki templatelere benzer ama uygulama ve yapabilecekleri açısından oldukça farklıdır. Bu makalede bu yapının faydaları, neden ihtiyaç olduğu ve nasıl kullanılacağı konusuna   bir başlangıç yapılacaktır.

Generic Sınıflar Problem Aşaması

Klasik Push() ve Pop() metodları sağlayan bir stack veri yapısını düşünün. Genel amaçlı bir stack veri yapısı geliştirirken, onu değişik tiplerde verileri tutmak için kullanmak istersiniz. C# 1.1 de, Object tabanlı stack kullanmak zorundaydınız.


public class Stack
{
   object[] m_Items; 
   public void Push(object item)
   {...}
   public object Pop()
   {...}
}


Kod Blok 1 Object-tabanlı stack yapısının nasıl gerçekleştirildiğini gösteriyor. çünkü Object .Net in en temel veri tipidir. Ve bu sayede istenilen tipte veriler tutabilirsiniz stack veri yapısında. Örneğin integer bir değer için:


Stack stack = new Stack();
stack.Push(1);
stack.Push(2);
int number = (int)stack.Pop();

Kod Blok 1. Object-Tabanlı bir stack yapısı
public class Stack
{
   readonly int m_Size; 
   int m_StackPointer = 0;
   object[] m_Items; 
   public Stack():this(100)
   {}   
   public Stack(int size)
   {
      m_Size = size;
      m_Items = new object[m_Size];
   }
   public void Push(object item)
   {
      if(m_StackPointer >= m_Size) 
         throw new StackOverflowException();       
      m_Items[m_StackPointer] = item;
      m_StackPointer++;
   }
   public object Pop()
   {
      m_StackPointer--;
      if(m_StackPointer >= 0)
      {
         return m_Items[m_StackPointer];
      }
      else
      {
         m_StackPointer = 0;
         throw new InvalidOperationException("Boş stacktan pop yapamazsınız");
      }
   }
}
Ama Object-Tabanlı çözümde 2 problem karşımıza çıkmaktadır. İlk olarak performans sorunu. Dğer tipindeki veri tiplerini kullanırken, önce onu boxing ile object ye çevirip (boxing) stack a atmak daha sonrada onu istediğiniz değer tipine çevirmeniz (unboxing) gerekir. Boxing ve unboxing kendi başına bir performans sorunudur aynı zamanda daha fazla garbage collection manasınada gelir.Referans tipi veriler kullanırkende büyük sıkıntı yaratır. Çünkü bu tipleride Object tipinden  asıl tipe çevirmeniz gerekmektedir:
Stack stack = new Stack();
stack.Push("1");
string number = (string)stack.Pop();
İkinci (ve daha önemli olanı) is tip güvenliğidir. Çünkü derleyici size Object tipinden herhangi bir değeri cast yapabilmenize izin verir. Böylece derlenme zamanı tip güvenliğini kaybedersiniz. Örneğin aşağıdaki kod derlenme sırasında sorun çıkartmaz ama çalışma sırasında hata alırsınız:

Stack stack = new Stack();
stack.Push(1);
//Aşağısı derleme sırasında sorun çıkarmaz ama çalışırken hata alırsınız.
string number = (string)stack.Pop();
Bu problemleri tip-özel stack yaparak aşabilirsiniz. Mesela integer değerler için  IntStack kullanabilirsiniz:

public class IntStack
{
   int[] m_Items; 
   public void Push(int item){...}
   public int Pop(){...}
} 
IntStack stack = new IntStack();
stack.Push(1);
int number = stack.Pop();
String değerler için StringStack:

public class StringStack
{
   string[] m_Items; 
   public void Push(string item){...}
   public string Pop(){...}
}
StringStack stack = new StringStack();
stack.Push("1");
string number = stack.Pop();
Ama bu şekilde performans ve tip-güvenlik problemlerini çözmek bizi üçüncü bir probleme götürür — verimlilik. Tip-Özel veri yapıları yazmak can sıkıcı, aynı şeylerin tekrardan yazılması ve hata eğilimli bir yapıdır. Bir veri yapısındaki hatayı düzeltirken, diğer tipler için tanımlı yapılarıda düzeltmeniz gerekir. Sonuç olarak C# 1.1 geliştiricileri Object-tabanlı veri yapılarının pratik olmadığı ve kullanım özelliğinin kalmadığı sonucuna vardılar.

16 Nisan 2011 Cumartesi

Generic Sınıflar (C# Programlama Rehberi)

Generics, C# dili ve CLR (Common Language Runtime) 'nin  2.0 versiyonu ile geldi. Generics .NET Framework'ü, sınıf veya methodun tanımlanıp, client kodu tarafından başlatılana kadar bir veya birden fazla tipin tanımlanmasını erteleyen sınıf veya methodların tasarlanmasına olanak sağlayan, tip parametre konseptiyle, tanıştırdı. Örneğin bir generic tip pametresi T kullanarak, diğer clientın casting ve boxing operasyonlarının maliyetini ve risklerini düşünmeden kullanabileceği sınıflar yazabilirsiniz. Örnek kod aşağıdadır.


// Generic Classı tanımlayın
public class GenericList
{
void Add(T input) { }
}
class TestGenericList
{
private class OrnekSinif { }
static void Main()
{
// int tipinde bir liste tanımlayın
GenericList<int> list1 = new GenericList<int>();
// string tipinde bir liste tanımlayın
GenericList<string> list2 = new GenericList<string>();
// OrnekSinif tipinde bir liste tanımlayın
GenericList list3 = new GenericList();
}
}