Bu site emekli olmuştur. Arşiv amaçlı olarak BT AKADEMİ sponsorluğunda yayın hayatına devam etmektedir.




C#nedir?com
 
YAZAR HAKKINDA
Serkan Yazıcıoğlu
Serkan Yazıcıoğlu
http://www.csharpnedir.com/
İletişme geçmek için tıklayın.
5 Makalesi yayınlanmakta.
Yazar hakkında detaylı bilgi için tıklayın.
Yayınlanan diğer makaleleri için tıklayın.
İlgili etiketler: (object atandiginda ayrica bellekte boxing dolayisiyla generic hashtable interface kullanilan object sinifi sortedlist vermek yaklasik C# / VC#/.NET Serkan Yazıcıoğlu
 
YAZI HAKKINDA
Türü : Makale
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
Seviyesi : Orta
Kategori : C# / VC#/.NET
Yayınlanma Tarihi : 21.8.2007
Okunma Sayısı : 87507
Yorum Sayısı : 3     yorum yaz
Site İçi AramaSİTE İÇİ ARAMA
Üye Girişini AçÜye GİRİŞİ
Üye girişi için tıklayın.
Kullanıcı Adı
Şifre
 
Beni her zaman hatırla
Bir hafta boyunca kullanıcı bilgilerinizi kullanıcı çıkışı yapana kadar hatırlar. (Paylaşılan bilgisayarlarda önerilmez.)
 
Şifremi / Kullanıcı Adımı unuttum.
 
.net TV RSS Serbest KÖŞE (?)
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
emre TAŞ
Silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Turhal Temizer
Conda install environment.yml Package 24.11.2024
Turhal Temizer
Mac OS/X Removing CUDA 24.11.2024
Burak Selim Şenyurt
Rust ile ECS Yaklaşımını Anlamak 24.11.2024
Burak Selim Şenyurt
Birlikte Rust Öğrenelim Serisi 24.11.2024
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Uzman Abi
Her Yönüyle C# - Sefer Algan
Tüm Yönleriyle Koleksiyonlar(Collections)
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon
System.Collections veri saklama için kullanılan yegane sınıflarımızın bulunduğu isim alanıdır. Bu alan altındaki karışık sınıflar ve arayüzler hakkında yazılmış bilgiler her ne kadar fazla olsa da bazı belirsizlikleri giderememesi bu makaleyi yazmamdaki temel amaç olmuştur. Hangi sınıf nerde kullanılmalı, bu sınıfların farklılıkları neler, performansları nasıl gibi bazı soruları bu makalede birlikte arayalım.

Öncellikle hatırlatmak istediğim konu boxing işlemidir. Bir değer tipinin (int, bool, double vs.), referans tipine(delegate, interface, string, class) veya Object sınıfına dönüştürülmesi işlemine ’Boxing’, tersine ise ’Unboxing’ denmektedir. Örnek vermek gerekirse:

int i = 1;
object o = i; //Boxing
i = (Int32)o; //Unboxing
Bu işlem programın daha yavaş çalışmasına ve tipin objeye dönüşmesinden dolayı bellekte daha fazla yer tutmasına sebep olur. Dolayısıyla ne kadar az boxing eşittir o kadar verimli program.

System.Collections ve System.Collections.Generic isim alanları altındaki sınıfların ve arayüzlerin en çok bilinenleri aşağıdaki tabloda bulunmaktadır. Bunları gruplarsak;

System.Collections System.Collections.Generic
Non Generic Generic Karşılığı
Array
ArrayList
BitArray
-

HashTable
SortedList
-

Queue
Stack

IEnumerable
ICollection
IList
IDictionary

CollectionBase
ReadOnlyCollectionBase
DictionaryBase

List<T>
-
LinkedList<T>

Dictionary<TKey, TValue>
SortedList<TKey, TValue>
SortedDictionary<TKey, TValue>

Queue<T>
Stack<T>

IEnumerable<T>
ICollection<T>
IList<T>
IDictionary
<TKey, TValue>

Collection<T>
ReadOnlyCollection<T>
Öncelikle System.Collections sınıfına bir göz atalım. Bu isim alanının içindeki en çok kullanılan arayüzleri ve sınıfları soyağacına göre tablolaştırırsak:



Şimdide generic olmayan bu sınıf ve arayüzlerimize genel bir bakış atalım: 

-Array: Temel dizidir. Kötü yanı başlangıçta sınırlarının çizilmesi gerektiğidir. Dolayısıyla boş kaldığında bellekte gereksiz yere kalabalık yapar. Ayrıca indeks değeri belirlenen alanı aştığında da çalışma zamanında hata vermesi de bir diğer kötü yanıdır. Array sınıfı abstract bir sınıftır. Dolayısıyla new anahtar sözcüğü ile örneklendirilemez. Açıklamak gerekirse biz bir “string[] dizi” oluşturduğumuz zaman arka tarafta bir Array sınıfı örneklenir. Bu yapının faydası diziye istediğimiz türden bir nesne atabilme imkanımızdır. Her ne kadar başlangıç değeri, belleği fazladan kullansada boxing işlemi yapılmadığından bu değer biraz azalır. Array sınıfı IList arayüzünden türesede Add, Remove, Sort gibi temel metodlara sahip değildir. Ayrıca IndexOf, FindIndex gibi indeksleme metodlarını da kullanımımıza sunmaz. Bu yüzden esnek bir yapıya sahip değildir. Array sınıfı matris yapısında kullanılan yegane sınıftır.

-ArrayList: Dizinin benzeridir fakat sadece object tipinden verileri saklar. Dolayısıyla da gönderilen veri object değilse boxing işlemine tabi tutulur. Fakat belirli bir sınır vermemize gerek yoktur. Yeni nesne eklendikçe boyutunu otomatikman arttırır. Add, Remove, Sort ve indeksleme metodlarına sahip olması işlem yapmayı kolaylaştırır.

-BitArray: Sadece int, byte veya bool değerler almaktadır. Değişkenlerin bit değerleri ile işlem yapmak için kullanılır. Başlangıçta sınır vermek zorunludur.

-HashTable ve Sorted List: Bu iki sınıfın çalışma prensipleri birbirine çok yakındır. Bir bölgede iki adet veri barındırırlar. Bunlar ‘Key’ ve ‘Value’dur. Verdiğimiz ‘Key’ değeri unique olmak ve null olmamak zorundadır. HashTable ve SortedList, verilere ulaşırken barındırdıkları unique anahtarları kullanarak ulaşırlar. Böylece aldıkları verilere bir nevi Identity kolonuna bağlamış olurlar. Key değerleri atandıktan sonra asla değişmez. Verileri eklerken kendi içlerinde ‘Key’lerine göre sıralarlar. HashTable bu işlemi Hash kodlarına göre SortedList ise alfabetik sıralamaya göre yapar. Bu işlem HashTable sınıfının performansını yükseltsede verilerin düzensiz saklanmasını sağlar. Boyut belirtme zorunluluğu yoktur ve arama performansları çok yüksektir. SortedList, HashTable’a göre her ne kadar daha yavaş olsa da IndexOfKey, IndexOfValue, RemoveAt, GetByIndex, SetByIndex gibi metodları barındırırak indekslemeyi daha esnek kılar.

-Stack ve Queue:
Stack LIFO, Queue ise FIFO mantığına göre çalışır. İçlerindeki verilerde dolaşma imkanı yoktur. Sadece en sondaki veya en baştaki veriye ulaşılabilir. Bunun açıklaması şudur: en baştaki veriye gitmek için sırayla tüm verilerin silinmesi gerekir. Boyut belirtme zorunluluğu yoktur, kendi otomatik olarak arttırır.

Arayüzler IEnumerable: Bilmemiz gereken en önemli arayüzdür ve collection isim alanının en üstündedir. IEnumerable ve IEnumerator arayüzleri foreach yapısının temelidir. Dizi bazlı bir sınıf yaptığımızda, foreach yardımıyla bir iterasyon yapmak istersek sınıfımızı bu arayüzlerden türetmeliyiz. IEnumerable arayüzü IEnumerator arayüzünden gelen GetEnumerator metodunu kullanır. GetEnumerator metodu ise MoveNext adlı bir metoda sahiptir. Bu metodu kullanarak ileriye doğru tüm koleksiyon içinde dolaşılabilir. C#’ta tüm koleksiyonlar IEnumerable arayüzünü implemente etmektedir. Bu da demektir ki biz foreach yardımıyla hepsinin içinde dolaşabilme imkanına sahibiz.   

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}
 
public interface IEnumerator
{
    object Current { get; }
    bool MoveNext();
    void Reset();
}
GetEnumerator metodunun kullanımına bir örnek vermek gerekirse:

ArrayList aryList = new ArrayList(); 
IEnumerator numerator = aryList.GetEnumerator();

while (numerator.MoveNext())
{
    object obj = numerator.Current;
    //Current özelliği bize numeratorün üzerinde bulunduğu nesneyi getirir. MoveNext metodu ise iterasyon bitene kadar çalışır.
}
 
foreach (object obj in aryList)
{
    //foreach döngüsü ile yukarıdaki numerator, tamamen aynı işlevi görmektedir.
}
ICollection:
Bu interface de tüm koleksiyonlar tarafından kullanılmaktadır. Count adlı çok bilindik bir özelliği barındırmaktadır. Ayrıca 2 adet thread özelliği bulunmaktadır.

public interface ICollection : IEnumerable
{
    int Count { get; }
    bool IsSynchronized { get; }
    object SyncRoot { get; }
    void CopyTo(Array array, int index);
}
IList:
Add, Clear, Contains, IndexOf, Insert, Remove, RemoveAt gibi en çok kullanılan koleksiyon metodlarını barındırır. Ayrıca indeksleyici içerir.

public interface IList : ICollection, IEnumerable
{
    bool IsFixedSize { get; }
    bool IsReadOnly { get; }
    object this[int index] { get; set; }
    int Add(object value);
    void Clear();
    bool Contains(object value);
    int IndexOf(object value);
    void Insert(int index, object value);
    void Remove(object value);
    void RemoveAt(int index);
}
IDictionary:
HashTable, SortedList gibi sınıfların implemente olduğu arayüzdür. Key ve value değerleri için Icollection arayüzünü kullanır. Ayrıca Add, Clear, Contains ve Remove metodlarını içerir. Key değerine göre de bir indeksleyici barındırır. Bu arayüzlü koleksiyonların seçilme sebebi indeks değerlerinin sabit kalma isteğidir. Bir veri silindiğinde arkasındaki verilerin indeks değerleri sabit kalır.

public interface IDictionary : ICollection, IEnumerable
{
    bool IsFixedSize { get; }
    bool IsReadOnly { get; }
    ICollection Keys { get; }
    ICollection Values { get; }
    object this[object key] { get; set; }
    void Add(object key, object value);
    void Clear();
    bool Contains(object key);
    IDictionaryEnumerator GetEnumerator();
    void Remove(object key);
}
Generic Mimari 

System.Collections.Generic isim alanı projeye eklendiğinde karşımıza 7 yeni sınıf çıkmaktadır; Dictionary, SortedDictionary, LinkedList, List ve tanıdık gelen Queue, Stack ve SortedList. İsimleri farklı olsa da generic sınıflardan sadece 1 tanesi (LinkedList<>) tamamen farklıdır. Diğerleri generic olmayan akrabalarıyla benzer şekilde çalışmaktadır.

-List<>: Heralde en verimli olan dolayısıyla da en çok kullanılan güzide sınıfımızdır. ArrayList sınıfının generic versiyonudur.

-LinkedList<>: Node yapısına sahip bir listedir. İçindeki her bir node hem önündekine hem arkasındakine bir göstericiyle bağlıdır. Doubly sıfatını almasının sebebi işte bu çift taraflı ilişkidir. (Ek bir bilgi vermek gerekirse: LinkedList sınıfının C’deki kuzeni sadece önündekiyle ilişkilidir, dolayısıyla singly LinkedList olarak anılır.) Yeni bir node eklenmek istendiğinde LinkedListNode<> sınfı kullanılır. Bu sınıfın kullanımı çok pratik değildir ve özel durumlarda kullanılmalıdır. İçindeki nodelara Next ve Previous metodlarıyla ulaşılır. İndeksleme yapılamadığından, Find metoduyla arama yapılır ve bu da tüm listenin içinde dolaştığından bize maliyeti fazla olur.

-Dictionary<> ve SortedList<>: Hash Table ve SortedList yapısını kullanmaktadırlar. Tek fark Key ve Value değerlerinin generic olmasıdır. Bu da her bir veri için iki adet boxing işleminden kurtulmak demektir. Bu da bize çok fazla performans artışı sağlar.

-SortedDictionary<>: Bu koleksiyon HashTable ve SortedList sınıflarının yoğurulmasıyla oluşmuş bir sınıftır. Aralarında çok ince farklar vardır. SortedList’ten daha fazla bellek kullanır. Hız bakımından ise SortedList’ten bazı durumlara göre yavaş veya hızlıdır. HashTable sınıfının bize sunduğu tüm imkanları bu sınıfta sağlar. Fakat verileri hash kodlarına göre değil, sıralama yaparak bellekte tutar. Bu bakımdan da SortedList sınıfını andırır.

IDictionary tabanlı nesnelerin nasıl sıralama yaptığı ile ilgili şu kodu yazarak bir test yaparsak:

Hashtable hashTable = new Hashtable();
hashTable.Add("5", "m");
hashTable.Add("4", "as");
hashTable.Add("1", true);
hashTable.Add("3", "bir");
hashTable.Add("2", "2");
hashTable.Add("6", 123);
hashTable.Add("a", "öxmcnxö");
hashTable.Add("c", "c");
hashTable.Add("z", "a");
 
listBox1.Items.Add("HASH TABLE");
foreach (object obj in hashTable.Values)
{
    listBox1.Items.Add(obj.ToString());

 
Dictionary<object, object> dictionary = new Dictionary<object, object>();
dictionary.Add("5", "m");
dictionary.Add("4", "as");
dictionary.Add("1", true);
dictionary.Add("3", "bir");
dictionary.Add("2", "2");
dictionary.Add("6", 123);
dictionary.Add("a", "öxmcnxö");
dictionary.Add("c", "c");
dictionary.Add("z", "a");
 
listBox2.Items.Add("DICTIONARY<>");
foreach (object obj in dictionary.Values)
{
    listBox2.Items.Add(obj.ToString());

 
SortedDictionary<object, object> sortedDictionary = new SortedDictionary<object, object>();
sortedDictionary.Add("5", "m");
sortedDictionary.Add("4", "as");
sortedDictionary.Add("1", true);
sortedDictionary.Add("3", "bir");
sortedDictionary.Add("2", "2");
sortedDictionary.Add("6", 123);
sortedDictionary.Add("a", "öxmcnxö");
sortedDictionary.Add("c", "c");
sortedDictionary.Add("z", "a");
 
listBox3.Items.Add("SORTED DICTIONARY<>");
foreach (object obj in sortedDictionary.Values)
{
    listBox3.Items.Add(obj.ToString());

 
SortedList sortedList = new SortedList();
sortedList.Add("5", "m");
sortedList.Add("4", "as");
sortedList.Add("1", true);
sortedList.Add("3", "bir");
sortedList.Add("2", "2");
sortedList.Add("6", 123);
sortedList.Add("a", "öxmcnxö");
sortedList.Add("c", "c");
sortedList.Add("z", "a");
 
listBox4.Items.Add("SORTED LIST");
foreach (object obj in sortedList.Values)
{
    listBox4.Items.Add(obj.ToString());

 
SortedList<object, object> sortedListGeneric = new SortedList<object, object>();
sortedListGeneric.Add("5", "m");
sortedListGeneric.Add("4", "as");
sortedListGeneric.Add("1", true);
sortedListGeneric.Add("3", "bir");
sortedListGeneric.Add("2", "2");
sortedListGeneric.Add("6", 123);
sortedListGeneric.Add("a", "öxmcnxö");
sortedListGeneric.Add("c", "c");
sortedListGeneric.Add("z", "a");
 
 
listBox5.Items.Add("SORTED LIST<>");
foreach (object obj in sortedListGeneric.Values)
{
     listBox5.Items.Add(obj.ToString());
}
Bu kod çalıştığında şu sonuç çıkmaktadır:



Görüldüğü üzere SortedDictionary<> ve her iki SortedList aynı şekilde çalışmışlardır. Önce numerik key değerlerini küçükten büyüğe sıralayıp dizmişlerdir. Sonrasında kalanları alfabetik sıraya göre eklemişlerdir.

HashTable hash kodlarına göre dizdiğinden belirli bir sıralaması yoktur.Algoritması bu kodların içinde gizlidr. Dictionary<> ise verilerin ekleniş sırasını hiç değiştirmeden saklamıştır.

Eğer key değerlerinin tiplerini birbirinden farklı yaparsak şöyle bir sonuç elde ederiz.

object o = false;
X.Add("5", "m");
X.Add("4", "as");
X.Add(1, true);
X.Add(3, "bir");
X.Add("2", "2");
X.Add("6", 123);
X.Add("a", "öxmcnxö");
X.Add(o, "c");
X.Add("z", "a");


Dictionary<> sınıfı gene eklendiği sırayı bozmadan belleğe almıştır. HashTable ise önce string anahtarları sonra, diğer anahtarları hash algoritmasına göre sıralamıştır. Diğer 3 sınıfın sonucu ise hüsran olmuştur. Aşağıda görüldüğü üzere sorted sıfatlı sınıflarımız karşılaştırma hatası vermişlerdir. Bunun sebebi ise IComparer arayüzünden gelen Comparer adlı özelliği bulundurmalarıdır.



Sonuç olarak System.Collections isim alanı altında karşımıza 7 adet non-generic ve 7 adette generic sınıf çıkmaktadır. Asıl önemli olan doğru sınıfı doğru yerde kullanmaktır. Bu yüzden her bir koleksiyonun performansını ve nerede kullanılması gerektiğini iyi bilmek gerekir. Makalemizin son kısmında, tüm koleksiyonlar kullanım amaçları için gruplandırılmış olup aşağıdaki test koduyla ayrı ayrı performans testleri yapılmıştır.

List<int> list = new List<int>();
int value = 0;

System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();

for (int i = 0; i < 1000000; i++)
{
     list.Add(i);
}
for (int i = 0; i < 1000000; i++)
{
     value = list[i];
}

watch.Stop();
Console.WriteLine(watch.Elapsed);
Listeleme Koleksiyonları 

Array
   ArrayList
   List<>
BitArray
   LinkedList<>
*Değer Tipi atandığında yaklaşık değerler
(Örnekte ‘int’ kullanılmıştır):


1.Array (int[]): 00.1264
2.List<int>: 00.4132
3.ArrayList: 02.6250

*Referans tipi atandığında yaklaşık değerler
(‘Class’ kullanılmıştır):

1.Array (MyClass[]): 00.2376
2.List<MyClass>: 00.6224
3.ArrayList: 00.6721

*Object dizileri kullanıldığı zaman:
1.Array(object[]): 02.1963
2.List<object>: 02.8552
3.ArrayList: 02.8726

*Bellek kullanımı
(1 milyon değer için):

İşlemci       ArrayList      List<int>
32-bit         19MB           8MB         
64-bit         39MB           8.1MB
Yukarıda görüldüğü üzere Array sınıfı her halükarda en hızlı sınıftır. Fakat bellekte fazla yer tutar. Bellek kullanımı için en uygun koleksiyon List<>’dir. Dolayısıyla hız istenirse Array, az bellek kullanımı istenirse List<> tercih edilmelidir. Eğer koleksiyona eklenicek tip belirli değilse ArrayList kullanılabilir. Fakat aynı işlevi generic listemizde karşılayabilme yetisine sahiptir.

dip not: BitArray ve LinkedList<> sınıflarının kullanım amacı farklı olduğundan teste tabi tutmaya gerek görmedim.

IDictionary Arayüzlü Koleksiyonlar

HashTable
   Dictionary
SortedList
   SortedList<>
SortedDictionary<>
*Değer Tipi atandığında yaklaşık değerler
(‘int’ kullanılmıştır):

1.Dictionary<int,int>: 02.9887
2.SortedList<int,int>: 07.4509
3.HashTable: 11.0872
4.SortedDictionary<int,int>: 36.2299
5.SortedList: 40.4208

*Referans tipi atandığında yaklaşık değerler
 (‘Class’ kullanılmıştır):

1.Dictionary<int,MyClass>: 03.0526
2.SortedList<int,MyClass>: 07.4548
3.HashTable: 08.0603
4.SortedList: 36.8587
5.SortedDictionary<int,MyClass>:47.3536
Dictionary<> ve SortedList<> sınıfları için herhalde söylenicek söze gerek yoktur. Generic sınıflarımız 1.0’daki atalarına göre çok daha hızlıdır. SortedDictionary<> ise özel durumlar için tercih edilmelidir.

FIFO / LIFO Koleksiyonları

Stack
   Stack<>
Queue
   Queue<>
 
*Değer Tipi atandığında yaklaşık değerler
(‘int’ kullanılmıştır):


1.Stack<int>: 00.7244
2.Queue<int>: 01.3969
3.Stack: 02.6948
4.Queue: 03.7186

*Referans tipi atandığında yaklaşık değerler
(‘Class’ kullanılmıştır):

1.Stack: 00.7607
2.Stack<MyClass>: 00.9163
3.Queue<MyClass>: 01.3468
4.Queue: 01.3865
Bu tablo için ise yoruma gerek yoktur. Stack sınıfı Queue sınıfına göre daha hızlıdır.

Bu makalenin genel olarak en önemli sonucu heralde generic mimarinin c sharp’a ne kadar hız kattığıdır. Geriye kalan ise yazılım geliştiricilerin doğru sınıfı kullanabilme kabiliyitlerinde gizlidir. Herkese bol koleksiyonlu günler.

Serkan Yazıcıoğlu
[email protected]

Kaynak: http://blogs.msdn.com/joshwil/archive/2004/04/13/112598.aspx
Makale:
Tüm Yönleriyle Koleksiyonlar(Collections) C#, Visual C# ve .NET Serkan Yazıcıoğlu
  • Yazılan Yorumlar
  • Yorum Yaz
ŞUB
8
2012
arkadaşım beni affedin ama Şu programcı milletinin kendini büyük görmesinden ve şu şurda gizlidir bu burda gizlidir gibi saçma sapan laflar etmesi beni çıltırdıyor. Hiçkimse allah kadar bilemez biraz alçak gönüllü ve saygılı olun.
EKİ
13
2009
Yazı için Teşekkürler. Arraylerde olduğu gibi Collectionlarda Tek tek Add metodunu çağırmadan bir seferde komple doldurmanın yolu var mı? {("key1","value1"),("key2","value2"),("key3","value3"),} gibi...
OCA
28
2008
Collection lar ile ilgili her ayrintiyi aciklayan, cok yararli bir makale. eline saglik ve tesekkürler...
Sayfalar : 1 
Yorum yazabilmek için üye girişi yapmalısınız. Üye girişi için tıklayın.
Üye değilseniz Üyel Ol linkine tıklayarak üyeliğinizi hemen başlatabilirisniz.
 
  • Bu Konuda Son 10
  • Eklenen Son 10
  • Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor