Ringkasan jenis generik

Pengembang menggunakan generik sepanjang waktu di .NET, baik secara implisit maupun eksplisit. Saat Anda menggunakan LINQ di .NET, apakah Anda pernah menyadari bahwa Anda bekerja dengan IEnumerable<T>? Atau jika Anda pernah melihat sampel online dari "repositori generik" untuk berbicara dengan database menggunakan Kerangka Kerja Entitas, apakah Anda menyadari bahwa sebagian besar metode mengembalikanIQueryable<T>? Anda mungkin bertanya-tanya apa itu T dalam contoh ini dan mengapa ada di sana.

Pertama kali diperkenalkan dalam .NET Framework 2.0, generik pada dasarnya adalah "templat kode" yang memungkinkan pengembang untuk menentukan struktur data jenis aman tanpa berkomitmen pada jenis data aktual. Misalnya, List<T> adalah koleksi generik yang dapat dideklarasikan dan digunakan dengan jenis apa pun, seperti List<int>, List<string>, atau List<Person>.

Untuk memahami mengapa generik bermanfaat, mari kita lihat kelas tertentu sebelum dan sesudah menambahkan generik: ArrayList. Dalam .NET Framework 1.0, elemen ArrayList berjenis Object. Elemen apa pun yang ditambahkan ke koleksi diam-diam diubah menjadi Object. Hal yang sama akan terjadi saat membaca elemen dari daftar. Proses ini dikenal sebagai kotak dan pembukaan kotak, dan berdampak pada performa. Bagaimanapun, selain performa, tidak ada cara untuk menentukan jenis data dalam daftar pada waktu kompilasi, yang membuat beberapa kode rapuh. Generik memecahkan masalah ini dengan menentukan jenis data yang akan dikandung setiap contoh daftar. Misalnya, Anda hanya dapat menambahkan bilangan bulat ke List<int> dan hanya menambahkan Orang ke List<Person>.

Generik juga tersedia selama runtime. Runtime tahu jenis struktur data yang Anda gunakan dan dapat menyimpannya dalam memori dengan lebih efisien.

Contoh berikut adalah program kecil yang menggambarkan efisiensi dari mengetahui jenis struktur data selama durasi:

  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();
      }
    }
  }

Program ini menghasilkan output yang serupa dengan teks berikut:

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

Hal pertama yang dapat Anda perhatikan di sini adalah bahwa menyortir daftar generik secara signifikan lebih cepat daripada mengurutkan daftar non-generik. Anda mungkin juga memperhatikan bahwa jenis untuk daftar generik berbeda ([System.Int32]), sedangkan jenis untuk daftar non-generik digeneralisasi. Karena runtime mengetahui jenis generik List<int> adalah jenis Int32, runtime dapat menyimpan elemen daftar dalam array bilangan bulat yang mendasarinya dalam memori, sementara non-generik ArrayList harus melemparkan setiap elemen daftar ke objek. Seperti yang ditunjukkan oleh contoh ini, konversi eksplisit tambahan membutuhkan waktu dan memperlambat pengurutan daftar.

Keuntungan tambahan dari runtime mengetahui jenis generik adalah pengalaman penelusuran kesalahan yang lebih baik. Saat Anda menelusuri kesalahan generik di C#, Anda mengetahui jenis setiap elemen yang ada dalam struktur data Anda. Tanpa generik, Anda tidak akan mengetahui jenis dari setiap elemen itu.

Lihat juga