C# cơ bản .NET Core
Partial, Nested (Bài trước)

Phương thức với kiểu Generic

Generic là kiểu đại diện, nó cho phép tạo mã nguồn code không phụ thuộc vào kiểu dữ liệu cụ thể, chỉ khi code thực thi thì kiểu cụ thể mới xác định. Trước đây bạn đã quen với việc viết code trên những kiểu dữ liệu cụ thể như int, float, double ... hay các class do bạn định nghĩa, tuy nhiên có những giải thuật giống nhau trên những kiểu dữ liệu khác nhau, để tránh việc viết nhiều lần code lặp lại thì lúc này áp dụng Generic - kiểu đại diện để xây dựng phương thức hoặc lớp.

Ví dụ bạn cần chuyển đổi giá trị lưu trong hai biến kiểu int, thì bạn có thể xây dựng phương thức theo cách thông thường như sau:

// phương thức này tráo đổi giá trị giữa hai biến kiểu int
public static void Swap(ref int a, ref int b) {
    int c = a;
    a = b;
    b = c;
}

Tuy nhiên, nếu cần tráo đổi giá trị giữa hai biến kiểu string thì phương thức trên không dùng được, bạn lại cần xây dựng một phương thức khác dành cho tham số kiểu string

// phương thức này tráo đổi giá trị giữa hai biến kiểu int
public static void Swap(ref string a, ref string b) {
    string c = a;
    a = b;
    b = c;
}

Bạn nhận thấy, giải thuật giải quyết bài toán giống nhau nhưng tham số khác nhau dẫn đến bạn phải viết hai đoạn code. Với những trường hợp như trên, logic giống nhau trên những kiểu dữ liệu khác nhau thì sẽ dùng đến Generic, thay vì viết code trên kiểu dữ liệu cụ thể thì code trên những kiểu chung chung.

Khai báo phương thức Generic

Bạn khai báo phương thức có sử dụng kiểu Generic chung chung bằng cách, chỗ nào là kiểu dữ liệu cụ thể thì thay nó bằng tên kiểu Generic, tên này là do bạn đặt một cách thống nhất tùy chọn như A, B, T, .... Trong đó sau phần tên hàm phải liệt kê ra tên những kiểu Generic mà bạn sẽ sử dụng cho hàm. Một khai báo tổng quát như sạng sau:

X MyFunction<X, Y>(X x, Y y)
{
   return x;
}

Khai báo phương thức có tên MyFunction, sau tên này bạn thấy có ký hiệu <X, Y> có nghĩa phương thức này có sử dụng hai kiểu là kiểu X và kiểu Y (tất nhiên nó chưa cụ thể là kiểu gì, nó chỉ cụ thể khi phương thức được gọi). Khi đã có kiểu Generic rồi thì dùng kiểu này cho các thành phần của phương thức - như kiểu trả về là X, tham số là kiểu XY, trong thân phương thức tương tự có thể khai báo sử dụng kiểu X và kiểu Y

Lúc này khi bạn gọi bạn chỉ cần đền tên X và Y theo kiểu cụ thể trong ký hiệu < ... >:

int a = 1;
string b = 2;
int rs = MyFunction<int, string>(a, b);  // Phương thức chạy với vai trò X là kiểu int, Y là kiểu string.

double c = 2;
MyFunction<double, int>(c, a);           // Phương thức chạy với X là kiểu double, Y kiểu int

Ví dụ dùng phương thức Generic

Áp dụng xây dựng hàm Swap ở trên:

static void Swap<T>(ref T a, ref T b)
{
    T c = a;
    a = b;
    b = c;
}

Khi sử dụng, bạn gọi phương thức chỉ việc thay chữ T bằng kiểu cụ thể muốn áp dụng

public static void TestSwap()
{
  int a = 1;
  int b = 2;
  Swap<int>(ref a, ref b);                       // Hàm trên kiểu T = int
  System.Console.WriteLine($"a = {a}; b = {b}"); // a = 2; b = 1

  string a1 = "A";
  string b1 = "B";
  Swap<string>(ref a1, ref b1); // Hàm trên kiểu T = string
  System.Console.WriteLine($"a1 = {a1}; b1 = {b1}"); // a1 = B; b1 = C
}

Tham khảo mã nguồn ví dụ: CS017_GenericCollect (Method) - Git hoặc tải về ex017-1 (Phương thức với kiểu Generic)

Lớp với kiểu Generic

Tương tự như phương thức, cũng có thể khai báo lớp với Generic - bằng liệt tên các kiểu đại diện này sau khai báo tên lớp

class MyClass<X, Y> {
// ...
}

Xây dựng lớp với kiểu Generic phổ biến để triển khai nhiều loại giải thuật như hàng đợi Queue, Stack, Array ...

class MyClass<T>
{
    private T bien;

    public MyClass(T value)
    {
        bien = value;
    }

    public T TestMethod(T pr)
    {
        Console.WriteLine(pr);
        return bien;
    }

    public T thuoctinh { get; set; }
}

Ví dụ sử dụng

MyClass<double> myClass = new MyClass<double>(123.123);
myClass.TestMethod(123); // in ra 123

Tham khảo mã nguồn ví dụ: CS017_GenericCollect (Method) - Git hoặc tải về ex017-2 (Lớp với kiểu Generic)


Đăng ký nhận bài viết mới
Partial, Nested (Bài trước)