Genel türlere genel bakış

Geliştiriciler örtük veya açık bir şekilde .NET'te genelleri her zaman kullanır. .NET'te LINQ kullandığınızda, birlikte IEnumerable<T>çalıştığınızı fark ettiniz mi? Alternatif olarak, Entity Framework kullanarak veritabanlarıyla konuşmaya yönelik bir "genel deponun" çevrimiçi örneğini görüyorsanız, çoğu yöntemin döndürdüğünü IQueryable<T>gördünüz mü? Bu örneklerde T'nin ne olduğunu ve neden orada olduğunu merak etmiş olabilirsiniz.

İlk olarak .NET Framework 2.0'da kullanıma sunulan genel öğeler, geliştiricilerin gerçek bir veri türüne işlemeden tür açısından güvenli veri yapıları tanımlamasına olanak tanıyan bir "kod şablonu" şeklindedir. Örneğin, List<T> bildirilebilen ve , List<string>veya List<Person>gibi List<int>herhangi bir türle kullanılabilen genel bir koleksiyondur.

Genel türlerin neden yararlı olduğunu anlamak için genel değerleri eklemeden önce ve ekledikten sonra belirli bir sınıfa göz atalım: ArrayList. .NET Framework 1.0'da ArrayList öğeler türündeydi Object. Koleksiyona eklenen tüm öğeler sessizce bir Objectöğesine dönüştürüldü. Listedeki öğeler okunurken de aynı durum yaşanırdı. Bu işlem kutulama ve kutu açma olarak bilinir ve performansı etkiler. Ancak performansın yanı sıra, derleme zamanında listedeki veri türünü belirlemenin bir yolu yoktur ve bu da bazı hassas kodlara neden olur. Genel değerler, her liste örneğinin içereceği veri türünü tanımlayarak bu sorunu çözer. Örneğin, öğesine yalnızca tamsayılar List<int> ve yalnızca Kişiler List<Person>ekleyebilirsiniz.

Genel öğeler çalışma zamanında da kullanılabilir. Çalışma zamanı, ne tür bir veri yapısı kullandığınızı bilir ve daha verimli bir şekilde bellekte depolayabilir.

Aşağıdaki örnek, çalışma zamanında veri yapısı türünü bilmenin verimliliğini gösteren küçük bir programdır:

  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Diagnostics;

  namespace GenericsExample {
    class Program {
      static void Main(string[] args) {
        //generic list
        List<int> ListGeneric = new List<int> { 5, 9, 1, 4 };
        //non-generic list
        ArrayList ListNonGeneric = new ArrayList { 5, 9, 1, 4 };
        // timer for generic list sort
        Stopwatch s = Stopwatch.StartNew();
        ListGeneric.Sort();
        s.Stop();
        Console.WriteLine($"Generic Sort: {ListGeneric}  \n Time taken: {s.Elapsed.TotalMilliseconds}ms");

        //timer for non-generic list sort
        Stopwatch s2 = Stopwatch.StartNew();
        ListNonGeneric.Sort();
        s2.Stop();
        Console.WriteLine($"Non-Generic Sort: {ListNonGeneric}  \n Time taken: {s2.Elapsed.TotalMilliseconds}ms");
        Console.ReadLine();
      }
    }
  }

Bu program aşağıdakine benzer bir çıkış oluşturur:

Generic Sort: System.Collections.Generic.List`1[System.Int32]
 Time taken: 0.0034ms
Non-Generic Sort: System.Collections.ArrayList
 Time taken: 0.2592ms

Burada fark ettiğiniz ilk şey, genel listeyi sıralamanın genel olmayan listeyi sıralamaktan önemli ölçüde daha hızlı olduğudur. Genel liste türünün ayrı ([System.Int32]) olduğunu, genel olmayan listenin türünün ise genelleştirilmiş olduğunu da fark edebilirsiniz. Çalışma zamanı genel List<int> türünün Int32olduğunu bildiği için, liste öğelerini temel alınan bir tamsayı dizisinde bellekte depolayabilir, genel ArrayList olmayanların ise her liste öğesini bir nesneye ataması gerekir. Bu örnekte gösterildiği gibi, ek atamalar zaman alır ve liste sıralamasını yavaşlatır.

Çalışma zamanının genel türünüzü bilmesinin bir diğer avantajı da daha iyi bir hata ayıklama deneyimidir. C# dilinde genel bir hata ayıklarken, her öğenin veri yapınızda ne tür olduğunu bilirsiniz. Genel değerler olmadan, her öğenin ne tür olduğunu bilemezsiniz.

Ayrıca bkz.