Tôi đã có thể định vị một bài viết Microsoft Connect thảo luận về vấn đề này một cách chi tiết:
Thật không may, hành vi này là theo thiết kế và không có một giải pháp dễ dàng nào cho phép sử dụng với các tham số loại có thể chứa các loại giá trị.
Nếu các loại được biết là loại tham chiếu, thì quá tải mặc định được xác định trên các biến kiểm tra đối tượng cho đẳng thức tham chiếu, mặc dù một loại có thể chỉ định quá tải tùy chỉnh của chính nó. Trình biên dịch xác định quá tải nào sẽ sử dụng dựa trên loại tĩnh của biến (xác định không phải là đa hình). Do đó, nếu bạn thay đổi ví dụ của mình để ràng buộc tham số loại chung T thành loại tham chiếu không được niêm phong (chẳng hạn như Ngoại lệ), trình biên dịch có thể xác định tình trạng quá tải cụ thể để sử dụng và đoạn mã sau sẽ biên dịch:
public class Test<T> where T : Exception
Nếu các loại được biết là loại giá trị, thực hiện kiểm tra công bằng giá trị cụ thể dựa trên các loại chính xác được sử dụng. Không có so sánh "mặc định" tốt ở đây vì các so sánh tham chiếu không có ý nghĩa đối với các loại giá trị và trình biên dịch không thể biết so sánh giá trị cụ thể nào để phát ra. Trình biên dịch có thể phát ra một cuộc gọi đến ValueType.Equals (Object) nhưng phương thức này sử dụng sự phản chiếu và khá kém hiệu quả so với các so sánh giá trị cụ thể. Do đó, ngay cả khi bạn chỉ định ràng buộc kiểu giá trị trên T, không có gì hợp lý để trình biên dịch tạo ở đây:
public class Test<T> where T : struct
Trong trường hợp bạn đã trình bày, trong đó trình biên dịch thậm chí không biết liệu T là giá trị hay loại tham chiếu, thì không có gì tương tự để tạo ra sẽ hợp lệ cho tất cả các loại có thể. So sánh tham chiếu sẽ không hợp lệ đối với các loại giá trị và một số loại so sánh giá trị sẽ gây bất ngờ cho các loại tham chiếu không quá tải.
Dưới đây là những gì bạn có thể làm...
Tôi đã xác nhận rằng cả hai phương thức này đều hoạt động để so sánh chung các loại giá trị tham chiếu và giá trị:
object.Equals(param, default(T))
hoặc là
EqualityComparer<T>.Default.Equals(param, default(T))
Để so sánh với toán tử "==", bạn sẽ cần sử dụng một trong các phương pháp sau:
Nếu tất cả các trường hợp T xuất phát từ một lớp cơ sở đã biết, bạn có thể cho trình biên dịch biết bằng cách sử dụng các hạn chế loại chung.
public void MyMethod<T>(T myArgument) where T : MyBase
Trình biên dịch sau đó nhận ra cách thực hiện các thao tác trên MyBase
và sẽ không ném "Toán tử '==' cho các toán hạng loại 'T' và 'T'" mà bạn hiện đang thấy.
Một lựa chọn khác là hạn chế T đối với bất kỳ loại nào thực hiện IComparable
.
public void MyMethod<T>(T myArgument) where T : IComparable
Và sau đó sử dụng CompareTo
phương thức được xác định bởi giao diện IComparable .
if (myArgument?.Equals( default(T) ) != null )
.