25 Mayıs 2011 Çarşamba

Metadata Nedir?

Son zamanlarda IT sektöründe sıkça duymaya alıştığımız ifadelerden biri oldu "metadata". Peki nedir bu metadata?
Birebir anlam olarak baktığımızda metadata, bilgi hakkında bilgi olarak tanımlanıyor. Ancak tabi bu haliyle soyut ve yetersiz bir tanımlama olarak kalıyor. Biraz somutlaştıralım:

Metadata, bilgi kaynaklarım beni yanıltmıyor ise ilk olarak kütüphanecilik alanında icat edilen bir kavram. Bir kütüphanede pek çok kitap, yani aslında yüklü miktarda bilgi bulunmaktadır. Ancak sorun, bu bilginin nasıl indexleneceği, yani hangi bilgiye hangi kitaplardan ulaşılabileceği, hangi kitabın içeriğinin aşağı yukarı ne olduğu... İşte burada metadata yani bilgi hakkında bilgi yardıma koşuyor. Metadata, ille de içeriğin türü hakkında (örneğin anahtar kelimeler veya bilimsel bir makalenin "abstract" kısmı) olmak zorunda değil. Basım evi, yayın tarihi, baskı sayısı da birer metadatadır.

Metadatanın IT alanındaki kullanımlarına çok basit örnekler vermek gerekirse, veritabanı sitemlerinde her tablonun ve alanın yanındaki onun hakkındaki açıklama alanları, web sitelerinin "header" bölümünde bulunan "meta tagleri" içindeki web sitesini tanımlayıcı bilgiler gösterilebilir.

IT ve otomasyon sistemleri yaygınlaştıkça, ortada çok büyük data, datadan üretilen enformasyon ve hatta işlenmiş bilgi havuzları oluştu. Şu an IT dünyasının gündemi, oluşan bu bilgiye en kısa yoldan nasıl ulaşılıp, bilginin nasıl yönetileceği olmaya başladı. Bu yüzden metadata kavramını gittikçe daha da çok duyacağız.

24 Mayıs 2011 Salı

Generic Kullanımı #2

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.
LinkedList list = 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 LinkedList where 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 LinkedList where K : IComparable
{...}
Kısıtlamalar gerçek türemelerden sonra yazılmalıdır. Mesela LinkedList IEnumerableinterface 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 LinkedList where K : IComparable,IConvertible
{...}

Her bir generic tip parametre için kısıtlama yazılabilir, mesela:
public class LinkedList where 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 MyClass where 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 Node where 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 LinkedList where 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 MyClass where T : struct 
{...}
Aynı şekilde referans tipinde olduğunuda class keywordü ile kısıtlayabilirsiniz:

public class MyClass where T : class 
{...}

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.