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 X
và Y
, 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)