Generics được giới thiệu trong C# 2.0. Generics cho phép bạn định nghĩa một lớp với trình giữ chỗ cho kiểu dữ liệu của trường, phương thức, tham số, v.v ... Generics thay thế các trình giữ chỗ này bằng một số kiểu dữ liệu cụ thể tại thời điểm biên dịch.
Một lớp generic có thể được định nghĩa bằng cách sử dụng cặp dấu <>. Ví dụ sau đây là một lớp generic đơn giản với biến thành viên , phương thức và thuộc tính generic.
class MyGenericClass<T>
{
private T genericMemberVariable;
public MyGenericClass(T value)
{
genericMemberVariable = value;
}
public T GenericMethod(T genericParameter)
{
Console.WriteLine("Parameter type: {0}, value: {1}", typeof(T).ToString(), genericParameter);
Console.WriteLine("Return type: {0}, value: {1}", typeof(T).ToString(), genericMemberVariable);
return genericMemberVariable;
}
public T GenericProperty { get; set; }
}
Như bạn có thể thấy trong đoạn mã trên, MyGenericClass có kèm theo <T> ở cuối. Cặp dấu <>
chỉ ra rằng MyGenericClass là một lớp generic và kiểu dữ liệu cơ bản sẽ được xác định sau, bây giờ xem nó là T . Bạn có thể sử dụng bất kỳ ký tự hoặc từ thay vì dùng T.
Bây giờ, trình biên dịch gán kiểu dữ liệu dựa trên kiểu dữ liệu được người gọi truyền vào khi khởi tạo một lớp. Ví dụ sau sử dụng kiểu dữ liệu int để khởi tạo:
var instance = new MyGenericClass<int>(10);
int val = instance.GenericMethod(200);
Đây là kết quả khi biên dịch và chạy chương trình:
Parameter type: int, value: 200
Return type: int, value: 10
Hình dưới đây minh họa cách trình biên dịch sẽ thay thế T bằng int trong MyGenericClass.
Lớp MyGenericClass<int>
sẽ được biên dịch, như ví dụ dưới đây.
class MyGenericClass
{
private int genericMemberVariable;
public MyGenericClass(int value)
{
GenericProperty = value;
}
public int GenericMethod(int genericParameter)
{
Console.WriteLine("Parameter type: {0}, value: {1}", typeof(int).ToString(), genericParameter);
Console.WriteLine("Return type: {0}, value: {1}", typeof(int).ToString(), genericMemberVariable);
return genericMemberVariable;
}
public int GenericProperty { get; set; }
}
Bạn có thể sử dụng bất kỳ kiểu dữ liệu nào khi khởi tạo MyGenricClass. Ví dụ sau sử dụng kiểu dữ liệu string
.
var instance = new MyGenericClass<string>("Hello Generic World");
instance.GenericProperty = "This is a generic property example.";
string result = instance.GenericMethod("Generic Parameter");
Đây là kết quả khi biên dịch và chạy chương trình:
Parameter type: string, value: Generic Parameter
Return type: string, value: Hello Generic World
Khi kế thừa từ một lớp generic, bạn cần phải chỉ định kiểu dữ liệu cho lớp cơ sở như dưới đây.
class MyDerivedClass : MyGenericClass<string>
{
//implementation
}
Tuy nhiên, nếu bạn muốn lớp dẫn xuất là lớp generic thì không cần chỉ định kiểu dữ liệu cho lớp generic cơ sở.
class MyDerivedClass<U> : MyGenericClass<U>
{
//implementation
}
Nếu lớp generic cơ sở có các ràng buộc, lớp dẫn xuất phải sử dụng các ràng buộc tương tự .
class MyGenericClass<T> where T: class
{
// Implementation
}
class MyDerivedClass<U> : MyGenericClass<U> where U: class
{
//implementation
}
Delegate định nghĩa chữ ký của phương thức mà nó có thể gọi. Một generic delegate có thể được định nghĩa giống như một delegate thông thương nhưng với kiểu dữ liệu generic.
Ví dụ sau minh họa generic delegate:
class Program
{
public delegate T Add<T>(T param1, T param2);
static void Main(string[] args)
{
Add<int> sum = AddNumber;
Console.WriteLine(sum(10, 20));
Add<string> concate = Concate;
Console.WriteLine(concate("Hello","World!!"));
Console.ReadKey();
}
public static int AddNumber(int val1, int val2)
{
return val1 + val2;
}
public static string Concate(string str1, string str2)
{
return str1 + str2;
}
}
Đây là kết quả khi biên dịch và chạy chương trình:
30
Hello World!!
Trong ví dụ trên, thêm đại biểu là chung. Trong phương thức Main (), nó đã xác định thêm đại biểu của tổng biến kiểu int. Vì vậy, nó có thể trỏ đến phương thức AddNumber () có tham số kiểu int. Một biến khác của add ủy nhiệm sử dụng kiểu chuỗi, vì vậy nó có thể trỏ đến phương thức Concate. Theo cách này, bạn có thể sử dụng các đại biểu chung cho các phương thức khác nhau của các loại tham số khác nhau.
Lưu ý: Một đại biểu chung có thể trỏ đến các phương thức với các loại tham số khác nhau. Tuy nhiên, số lượng tham số nên giống nhau.
Generics có thể được áp dụng cho những điều sau đây:
Những điểm cần nhớ:
C # bao gồm các ràng buộc để chỉ định loại loại giữ chỗ với lớp chung được cho phép. Nó sẽ đưa ra một lỗi thời gian biên dịch nếu bạn cố gắng khởi tạo một lớp chung bằng cách sử dụng một loại giữ chỗ không được cho phép bởi một ràng buộc. Ví dụ: nếu các ràng buộc chung chỉ định rằng chỉ có thể sử dụng loại tham chiếu với lớp chung thì bạn không thể sử dụng loại giá trị để tạo một đối tượng của loại chung.
Các ràng buộc có thể được áp dụng bằng cách sử dụng từ khóa where . Trong ví dụ sau, MyGenericClass chỉ định các ràng buộc mà chỉ một loại tham chiếu có thể được sử dụng với MyGenericClass. Điều này có nghĩa là chỉ một lớp có thể là một loại giữ chỗ chứ không phải các kiểu nguyên thủy, struct, v.v.
class MyGenericClass<T> where T: class
{
private T genericMemberVariable;
public MyGenericClass(T value)
{
genericMemberVariable = value;
}
public T genericMethod(T genericParameter)
{
Console.WriteLine("Parameter type: {0}, value: {1}", typeof(T).ToString(),genericParameter);
Console.WriteLine("Return type: {0}, value: {1}", typeof(T).ToString(), genericMemberVariable);
return genericMemberVariable;
}
public T genericProperty { get; set; }
}
Vì vậy, bây giờ, bạn không thể sử dụng int làm loại giữ chỗ. Sau đây sẽ cung cấp một lỗi thời gian biên dịch.
// error compile time
MyGenericClass<int> intGenericClass = new MyGenericClass<int>(10);
Chuỗi hoặc bất kỳ loại lớp nào là một loại hợp lệ vì nó là một loại tham chiếu.
MyGenericClass<string> strGenericClass = new MyGenericClass<string>("Hello World");
MyGenericClass<Student> strGenericClass = new MyGenericClass<Student>(new Student());
Bảng sau liệt kê các loại ràng buộc chung.
Ràng buộc | Miêu tả |
---|---|
where T : class | Kiểu dữ liệu phải là kiểu tham chiếu. |
where T : struct | Kiểu dữ liệu phải là kiểu giá trị. |
where T : new() | Kiểu dữ liệu phải có phương thức khởi tạo public không có tham số. |
where T : <base class name> | Kiểu dữ liệu phải là lớp cơ sở hoặc lớp kế thừa từ lớp cơ sở được chỉ định. |
where T : <interface name> | Kiểu dữ liệu phải interface hoặc lớp triển khai thực hiện giao diện được chỉ định. |
where T : U | Kiểu dữ liệu được cung cấp cho T phải là kiểu dữ liệu của đối số được cung cấp cho U hoặc lớp kế thừa từ đối số được cung cấp cho U. |
Một lớp chung có thể có nhiều ràng buộc như dưới đây.
class MyGenericClass<T, U> where T: class where U:struct
{
...
}
Bạn cũng có thể áp dụng các ràng buộc trên các phương thức chung.
class MyGenericClass<T> where T: class
{
public T genericMethod<U>(T genericParameter, U anotherGenericType) where U: struct
{
Console.WriteLine("Generic Parameter of type {0}, value {1}", typeof(T).ToString(),genericParameter);
Console.WriteLine("Return value of type {0}, value {1}", typeof(T).ToString(), genericMemberVariable);
return genericMemberVariable;
}
}
Vì vậy, các ràng buộc có thể được áp dụng trên các loại chung.
Những điểm cần nhớ:
where
.Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
Trong loạt bài này, tôi sẽ xem xét một số
Ngôn ngữ C# đã bật các bộ tăng áp liên
Trong bài viết này, chúng ta sẽ tìm hiểu lớp tiện ích ZipFile trong C#, cách nén tập tin và thư mục, cùng với giải nén tập tin zip.
Bài viết này sẽ giới thiệu cách đơn giản nhất mà tôi đã tìm thấy để đọc và ghi file Excel bằng C# sử dụng ExcelMapper.