C# - C Sharp: Generic

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Tổng quan

Generic là loại cấu trúc dữ liệu có tham số. Generic có thể làm việc với cả loại dữ liệu kiểu giá trị và loại dữ liệu kiểu tham chiếu; kiểu dữ liệu của generic khi định nghĩa sẽ là ở dạng chung chung, chưa cụ thể, và chính điều này sẽ giúp ích rất nhiều trong việc xây dựng những project có tính đơn giản hơn mà vẫn đạt hiệu quả tương ứng. Ta có thể định nghĩa lớp, interface, structure, phương thức và cả delegate như là kiểu generic trong C#.

Xét một chương trình C# sử dụng một biến mảng có kiểu Object để lưu trữ một danh sách tên của các sinh viên. Tên của sinh viên được đọc từ console có kiểu giá trị và được box để có thể lưu trữ theo kiểu Object. Trong trường hợp này trình biên dịch sẽ không thể xác minh được dữ liệu lưu trữ có cùng kiểu với kiểu dữ liệu mà bạn đã gán hay không, chẳng hạn như nếu bạn nhập vào dữ liệu là một số dữ liệu đó sẽ được box mà không được xác minh. 

Để đảm bảo an toàn kiểu và khắc phục được điều trên sử dụng generic sẽ là một lựa chọn; khi đó generic sẽ tạo ra một kiểu dữ liệu chung chung để rồi sẽ cụ thể hóa kiểu dữ liệu đó trong những tình huống cụ thể của bài toán.

Các Namespace, Class và Interface generic

Có một số namespace trong .NET Framework rất thuận tiện cho việc tạo và sử dụng các generic; ví dụ như namespace System.Collections.ObjectModel cho phép bạn tạo các tập hợp generic động và chỉ đọc, namespace System.Collections.Generic bao gồm các lớp và interface cho phép bạn định nghĩa các tập hợp generic tùy chỉnh, ...

Các lớp generic

Namespace System.Collections.Generic có chứa các lớp cho phép bạn tạo các tập hợp với kiểu an toàn; bảng dưới đây sẽ liệt kê các lớp được sử dụng phổ biến của namespace này:

Lớp Mô tả
Comparer Là một lớp trừu tượng cho phép ta tạo một tập hợp generic bằng cách thực thi các chức năng của interface IComparer
Dictionary.KeyCollection Bao gồm các key của thể hiện của lớp Dictionary
Dictionary.ValueCollection Bao gồm các value của thể hiện của lớp Dictionary
EqualityComparer Là một lớp trừu tượng cho phép ta tạo một tập hợp generic bằng cách thực thi các chức năng của interface IEqualityComparer

Các interface generic

Namespace System.Collections.Generic cũng chứa các interface cho phép bạn tạo các tập hợp với kiểu an toàn; bảng dưới đây sẽ liệt kê các lớp được sử dụng phổ biến của namespace này:

Interface Mô tả
IComparer Định nghĩa phương thức generic Comparer() dùng để so sánh các giá trị trong một tập hợp
INumerable Định nghĩa phương thức GetEnumerator() dùng để lặp (iterate) trên một tập hợp
IEqualityComparer Bao gồm các phương thức cho phép kiểm tra sự tương xứng giữa hai đối tượng bất kỳ

System.Collections.ObjectModel

Namespace này bao gồm các lớp có thể được dùng để tạo các tập hợp generic tùy chỉnh; bảng dưới đây sẽ liệt kê một số lớp của namespace này:

Lớp Mô tả
Collection<> Cung cấp lớp cơ sở cho các tập hợp generic
KeyedCollection<> Cung cấp một lớp trừu tượng cho một tập hợp với key và value tương ứng
ReadOnlyCollection<> Là một lớp generic cơ sở chỉ đọc dùng để ngăn ngừa sự thay đổi (modify) của tập hợp

Dưới đây là một ví dụ về việc sử dụng lớp ReadOnlyCollection<>:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Demo
{
  class ReadOnly
  {
    static void Main(string[] args)
    {
      List<string> objList = new List<string>();
      objList.Add("Francis");
      objList.Add("James");
      objList.Add("Baptista");
      objList.Add("Micheal");
      ReadOnlyCollection<string> objReadOnly = new ReadOnlyCollection
        <string>(objList);
      Console.WriteLine("Values stored in the read only collection");
      foreach (string str in objReadOnly)
      {
        Console.WriteLine(str);
      }
      Console.WriteLine();
      Console.WriteLine("Total number of elements in the read only collection: " + objReadOnly.Count);
      if (objList.Contains("Francis"))
      {
        objList.Insert(2, "Peter");
      }
      Console.WriteLine("\nValues stored in the list after modification");
      foreach (string str in objReadOnly)
      {
        Console.WriteLine(str);
      }
      string[] array = new string[objReadOnly.Count * 2];
      objReadOnly.CopyTo(array, 5);
      Console.WriteLine("\nTotal number of values that can be stored in the new array: " + array.Length);
      Console.WriteLine("Values in the new array");
      foreach (string str in array)
      {
        if (str == null)
        {
          Console.WriteLine("null");
        }
        else
        {
          Console.WriteLine(str);
        }
      }
    }
  }
}

Trong ví dụ trên, phương thức Main() của lớp ReadOnly tạo thể hiện có tên objList với một tham số kiểu string của lớp generic List; phương thức Add() sẽ thêm các phần tử vào thể hiện objList; phương thức Main() cũng tạo thể hiện có tên objReadOnly của lớp ReadOnlyCollection với một tham số kiểu string và các phần tử của thể hiện objList của lớp List sẽ được copy tới thể hiện này; phương thức Contains() sẽ kiểm tra xem thể hiện objList của lớp List có chứa phần tử với giá trị "Francis" hay không, nếu chứa thì sẽ thêm một phần tử mới có giá trị "Peter" vào objList tại vị trí có chỉ số là 2; phương thức Main() cũng tạo một biến mảng có tên array và có kích thước gấp đôi kích thước của thể hiện objReadOnly; phương thức CopyTo() sẽ tiến hành copy các phần tử của thể hiện objReadOnly vào mảng array và đặt các phần tử copy được vào vị trí có chỉ số bằng 5 trở đi. Kết quả của ví dụ trên được thể hiện ở hình dưới đây:

ObjectModel namespace

Tạo kiểu generic

Việc khai báo một generic luôn luôn phải có ít nhất một tham số kiểu và tham số kiểu sẽ được dùng để làm nơi giữ chỗ cho kiểu dữ liệu cụ thể sau này; kiểu dữ liệu cụ thể chỉ có thể được xác định khi kiểu generic được tham chiếu tới hoặc được khởi tạo trong chương trình.

Quá trình tạo một kiểu generic bắt đầu bằng việc định nghĩa kiểu generic với các tham số kiểu đi kèm; việc định nghĩa này đóng vai trò như là một bản thiết kế. Sau đó, các kiểu generic sẽ được tạo từ định nghĩa bằng cách xác định kiểu thực sự và sẽ thay thế cho các tham số kiểu hay các nơi giữ chỗ.

Ưu điểm của generic

Generic đảm bảo tính an toàn kiểu trong thời gian biên dịch chương trình. Generic cho phép ta dùng lại được các mã lệnh một cách an toàn mà không cần phải gán hay boxing. Mỗi định nghĩa kiểu generic có thể được sử dụng lại với các kiểu khác nhau nhưng tại một thời điểm chỉ sử dụng được một kiểu; cùng với khả năng sử dụng lại thì generic còn có một số khả năng nữa như sau:

· Tăng hiệu năng của chương trình, bởi vì chương trình sẽ sử dụng ít bộ nhớ hơn do không cần phải sử dụng các biện pháp gán hay boxing.

· Đảm bảo được mô hình lập trình định kiểu mạnh mẽ.

· Giảm được lỗi run-time có thể gây ra bởi không cần sử dụng đến gán và boxing.

» Tiếp: Tạo và sử dụng generic
« Trước: Dictionary generic
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!