Referans Tipleri (Reference Types)

10 Ara

Referans tipleri .Net Framework platformunda çok kullanılan tiplerdir. Referans tipleri büyük bir  esnekliğe sahip olmakla beraber metodlarda kullanılırken çok iyi performas sağlar.

Referans tipleri stack bölgesinde dataların bulunduğu adresleri depolarlar. Pointer olarakta adlandırılabilir. Adreslerin işaret ettiği asıl veriler ise belleğin heap adı verilen bölgesinde depolanmaktadır. Çalışma zamanı (Runtime) garbage collection diye bilinen bir mekanizma sayesinde bellek yönetimini kontrol etmektedir. Garbage collection ise çöp toplayıcı bir mekanizmadır. Yani belleği periyodik olarak kontrol eder ve bellekte artık kullanılmayan öğeri yok eder.

Referans ve Değer Tiplerinin Karşılaştırılması

Bir referans tipi adres bilgisi barındırdığı için bir referans tipi değişkenini başka bir referans tip değişkenine atadığımızda değişkenin sadece adresi kopyalanmış olur. Yani veriler kopyalanmaz. Sadece iki değişkende aynı heap bölgesini işaret etmektedir.

Örnerk:

Struct Selection
 {
      public int val;
      public Selection(int Val)
      {
        val=Val;
      }

      public override string ToString()
      {
         return val.ToString();
      }
 }

Selection adında bir structure hazırladık ve aşağıdaki gibi iki Selection tipini kopyalamaya çalışalım.


 Selection s1 = new Selection(0);
 Selection s2= s1;
 s1.val+=1;
 s2.val+=2;
 Console.WriteLine("s1 = {0},s2 = {1}", s1, s2);

Bu örnekte çıktı olarak “s1=1, s2=2” sonucunu alırız. Bunun sebebi struct tipinin bir değer tipi olmasıdır. Eğer Selection yapısının tipini class olarak değiştirirsek çıktı olarak “s1=3, s2=3” sonucunu alırız. Yani Selection tipini değiştirmekle değer tipinden referans tipine geçirmiş oluruz.

Built-in Referans Tipleri

.Net Framework bünyesinde 2500 den fazla mevcut (built-in) referans tipi barınmaktadır. Bunlardan en çok kullanılanlar aşağıdaki tabloda verilmektedir.

Type Kullanım
System.Object Framework’ün en genel tipidir. Bütün tiplerde bulunan ToString, GetType, Equals gibi metodları  bünyesinde barındırır.
System.String Text şeklindeki verileri tutar.
System.Text.StringBuilder Dinamik text verilerini tutar.
System.Array Dizileri temsil eder.
System.IO.Stream Dosya, aygıt ve network ortamında kullanılır.
System.Exception Sistem ve uygulama bazındaki istisnaları yakalar.

String ve StringBuilder sınıfları

Bu sınıflar test verilerini tuttukları gibi tuttukları veriler üzerinde işlem yapabilme yeteneğine de sahiptir.

Örneğin System.String sınıfı bünyesinde birçok üye bulundurmaktadır.


string s = "this is some text to search";

s = s.Replace("search", "replace");

Console.WriteLine(s);

System.String sınıfının bir başka özelliği ise değiştirilemez olmasıdır. İyi ama bu ne demek? Bu şu anlama geliyor; çalışma zamanında(runtime) esnasında string tipinede bir değişkende herhangi bir değişiklik yapmak demek eski string yerine yeni bir string oluşturmak demektir.

Örnerk:


string s;
s = "wombat";       // "wombat"
s += " kangaroo";  // "wombat kangaroo"
s += " wallaby";     // "wombat kangaroo wallaby"
s += " koala";         // "wombat kangaroo wallaby koala"

Console.WriteLine(s);

Yukardaki örnekte saadece son stringin referansı bulunmaktadır. Yani önceki üç veri çöptoplama esnasında yok edilecektir. Bu tür geçici işlemlerden uzak durmak performans açısından önemlidir. Bu durumdan kaçınmak için birkaç yol vardır.

  • String sınıfının Contact, Join veya Format metodlarını kullanarak bir string ifadesine birden çok öğeyi eklemek mümkündür.
  • StringBuilder sınıfını kullanarakdinamik olarak string oluşturmak mümkündür.

StringBuilder sınıfını kullanmak en esnek yöntemdir. Çünkü birden fazla  ifadeyi birleştirebilen bir yapıya sahiptir. Varsayılan kurucu metodu 16 bayt uzunluğunda bir tampona sahiptir. İhtiyaç oldukça genişleyebilmektedir. İsenilen büyüklükte başlangıç boyutu ve maksimum boyutu belirlenebilmektedir.

Örnek:


System.Text.StringBuilder sb = new System.Text.StringBuilder(30);
sb.Append("wombat");  // string oluştur.
sb.Append(" kangaroo");
sb.Append(" wallaby");
sb.Append(" koala");
string s = sb.ToString();    // onucu bir string değişkenine aktar.

Console.WriteLine(s);

String sınıfının diğer bir önemli özelliği ise System.Object operatörlerinin aşırı yüklenmesidir. Aşağıdaki tabloda string sınıfının aşırı yüklenmiş operatörleri verilmektedir.

Operatör C# İşlevi
Ekleme + İki string değişkenini birleştirir.
Eşitlik == İki string değişkenin aynı ieriğe eşit olup olmadığını kontrol eder.
Eşitsizlik != Eşitsizliği kontrol eder.
Atama = String ifasesini diğer bir string ifadesine kopyalar.

Diziler

Diziler C# dilinde köşeli parantezler ile ifade edilmektedir. String tipinde olduğu gibi System.Array sınıfının da kendine özgü üyeleri bulunmaktadır. Bu üyeler dizi içindeki verilerle çalışmaya yarar. Örneğin bir dizinin verilerinin sıralanması için şu metodu kullanabiliriz:

Array.Sort(array);

Diziyi tanımlamak ve dizinin verilerine ulaşmak ise şu şekildedir.


int[] array = { 5, 81, 2, 62 };

Array.Sort(array);

Console.WriteLine("{0}, {1}, {2}", array[0], array[1], array[2]);

Streams

Stream tipleri disk üzerine veri yazıp okuk veya ağ üzerinden iletişim sağlamak için kullanılır. System.IO.Stream tipi tüm stream tipler için temel oluşturur. Aşağıdaki tabloda en çok kullanılan stream tipler listelenmektedir. Ağ akışları için kullanılan stream tipler System.Network.Sockets ad uzayında bulunmaktadır.

System.IO Tipleri Kullanımları
FileStream Dosya okuma ve yazma işlemleri.
MemoryStream Bellek okuma yazma işlemleri.
StreamReader Akışkan ortam verilerini okumak için kullanılır.
StreamWriter Akışkan ortamlara veri yazmak için kullanılır.

En basit tipler olan StreamReader ve StreamWriter text dosyası oluşturmamızı sağlar. Varsayılan kurucu metoda dosya adını girerek tek satırda dosyaya erişmek mümkündür. Dosya ile işlem bittiğinde Close metodu çağrılarak dosya kilidi kaldırılmalıdır. Aşağıda dosya yazma ve okuma işlemine bir örnek verilmektedir.


StreamWriter sw = new StreamWriter("text.txt");
sw.WriteLine("Hello, World!");
sw.Close();

 StreamReader sr = new StreamReader("text.txt");
Console.WriteLine(sr.ReadToEnd());
sr.Close();

İstisnalar (Exception)

Bir uygulamanın beklenmedik durumlarda normal çalışmasını kesmek için kullanılır. Örneğin, taşınabilir bir disk üzerindeki çok fazla veri içeren bir dosyadan okuma işlemi gerçekleştirirken diskin çıkarıldığında uygulama okuma işlemine devam edemeyecektir.

İstisnalar(Exceptions) bu gibi durumlarda uygulamanın tamamen sonlamasını engellemek, oluşan hatanın yakalanmasın sağlamak için kullanılır. Aşağıda buna uygun bir örnek verilmektedir.

try
 {
    StreamReader sr = new StreamReader(@"C:\test.text");
    Console.WriteLine(sr.ReadToEnd());
 }
 catch (Exception ex)
 {
   Console.WriteLine("Error reading file: " + ex.Message);
 }

Yukardaki örnekte bir hata oluşması durumunda, oluşan hata catch bloğu tarafından yakalanacaktır. Eğer bir hata oluşmazssa cacth bloğu atlanacaktır.

Temel sınıf olan Exception sınıfının yanında .Net platformunda, System.SystemException sınıfından türemiş yüzlerce istisna sınıfı bulunmaktadır. Ayrıca System.ApplicationException sınıfından türeterek kendi istisna sınıflarımızı da oluşturabilirz.

Birden fazla istisnanın olduğu durumlarda hataların farklı türlerine göre farklı yanıt verilir. Bu durumda birden fazla cache bloğu hataları en özelden en genele doğru sıralayarak oluşrurulur.

Hata yakalama mekanizması try ve catch bloğu yanında bride finally bloğu vardır. Finally bloğu try ve catch bloklarından sonra çalışır. Bunu şöyle bir örnekle açıklayabiliriz. Örneğin bir dosyayı okumak StreamReader için açtınız ve dosya kilitlendi. Okuma işlemi bitip Close metodu çalışana kadar dosya açık kalacaktır. Bu gibi durumlarda finally bloğunda Close metodu çağrılabilir.

StreamReader sr = new StreamReader("text.txt");

try
{
  Console.WriteLine(sr.ReadToEnd());
}
catch (Exception ex)
{
  Console.WriteLine("Error reading file: " + ex.Message);
}
finally
{
  sr.Close();
}

Yukarıdaki Finally bloğundan Try bloğu içindeki değişkenlere erişilemediği için StreamReader nesnesi Try bloğu dışına tanımlanmıştır.

Genelde basit değişken tanımlamaları dığında herşey try bloğu içinde olmalıdır. Hata yakalama işlemi sayesinde uygulamalar daha kullanışlı hale getirilebilmektedir. Ancak bu işlemin performansa olumsuz yönde etkisi olmaktadır.

Bu yazıyla ilgili çalışan bir uygulamanın kodlarını buradan bulabilirsiniz.

Kaynak: MCTS Self-Paced Training Kit: Microsoft .Net Framework 2.0 Application Development Faundation