Có hai vấn đề ở đây: 1) thử nghiệm để xem liệu Loại có thể không; và 2) thử nghiệm để xem liệu một đối tượng đại diện cho Loại không thể.
Đối với sự cố 1 (kiểm tra Loại), đây là giải pháp tôi đã sử dụng trong các hệ thống của riêng mình: Giải pháp kiểm tra TypeIsNullable-check
Đối với vấn đề 2 (kiểm tra một đối tượng), giải pháp của Dean Powder ở trên hoạt động đối với các loại giá trị, nhưng nó không hoạt động đối với các loại tham chiếu, vì sử dụng quá tải <T> luôn trả về sai. Vì các loại tham chiếu vốn đã vô hiệu, nên việc kiểm tra một loại tham chiếu sẽ luôn trả về giá trị true. Vui lòng xem ghi chú [Giới thiệu về "nullable"] bên dưới để được giải thích về các ngữ nghĩa này. Vì vậy, đây là sửa đổi của tôi đối với cách tiếp cận của Dean:
public static bool IsObjectNullable<T>(T obj)
{
// If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
if (!typeof(T).IsValueType || obj == null)
return true;
// Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
return false;
}
public static bool IsObjectNullable<T>(T? obj) where T : struct
{
// Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
return true;
}
Và đây là sửa đổi của tôi đối với mã kiểm tra máy khách cho giải pháp trên:
int a = 123;
int? b = null;
object c = new object();
object d = null;
int? e = 456;
var f = (int?)789;
string g = "something";
bool isnullable = IsObjectNullable(a); // false
isnullable = IsObjectNullable(b); // true
isnullable = IsObjectNullable(c); // true
isnullable = IsObjectNullable(d); // true
isnullable = IsObjectNullable(e); // true
isnullable = IsObjectNullable(f); // true
isnullable = IsObjectNullable(g); // true
Lý do tôi đã sửa đổi cách tiếp cận của Dean trong IsObjectNullable <T> (T t) là cách tiếp cận ban đầu của anh ta luôn trả về sai cho loại tham chiếu. Vì một phương thức như IsObjectNullable sẽ có thể xử lý các giá trị loại tham chiếu và vì tất cả các loại tham chiếu đều là null, nên nếu một kiểu tham chiếu hoặc null được truyền, thì phương thức sẽ luôn trả về đúng.
Hai phương thức trên có thể được thay thế bằng phương thức đơn sau đây và đạt được cùng một đầu ra:
public static bool IsObjectNullable<T>(T obj)
{
Type argType = typeof(T);
if (!argType.IsValueType || obj == null)
return true;
return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
}
Tuy nhiên, vấn đề với cách tiếp cận phương thức đơn cuối cùng này là hiệu năng bị ảnh hưởng khi sử dụng tham số Nullable <T>. Phải mất nhiều thời gian xử lý hơn để thực thi dòng cuối cùng của phương thức này so với việc cho phép trình biên dịch chọn quá tải phương thức thứ hai được hiển thị trước đó khi tham số Nullable <T> -type được sử dụng trong lệnh gọi IsObjectNullable. Do đó, giải pháp tối ưu là sử dụng phương pháp hai phương pháp được minh họa ở đây.
CAVEAT: Phương thức này chỉ hoạt động đáng tin cậy nếu được gọi bằng cách sử dụng tham chiếu đối tượng ban đầu hoặc một bản sao chính xác, như trong các ví dụ. Tuy nhiên, nếu một đối tượng nullable được đóng hộp vào Loại khác (chẳng hạn như đối tượng, v.v.) thay vì còn lại ở dạng Nullable <> ban đầu, phương thức này sẽ không hoạt động đáng tin cậy. Nếu mã gọi phương thức này không sử dụng tham chiếu đối tượng gốc, không có hộp hoặc một bản sao chính xác, thì nó không thể xác định một cách đáng tin cậy tính vô hiệu của đối tượng bằng phương thức này.
Trong hầu hết các kịch bản mã hóa, để xác định tính không có giá trị, người ta phải dựa vào việc kiểm tra Loại của đối tượng ban đầu, chứ không phải tham chiếu của nó (ví dụ: mã phải có quyền truy cập vào Loại ban đầu của đối tượng để xác định tính không hợp lệ). Trong những trường hợp phổ biến hơn này, IsTypeNullable (xem liên kết) là một phương pháp đáng tin cậy để xác định tính không hợp lệ.
PS - Giới thiệu về "nullable"
Tôi nên lặp lại một tuyên bố về sự vô hiệu mà tôi đã thực hiện trong một bài đăng riêng biệt, áp dụng trực tiếp để giải quyết đúng chủ đề này. Đó là, tôi tin rằng trọng tâm của cuộc thảo luận ở đây không phải là làm thế nào để kiểm tra xem một đối tượng có phải là loại Nullable chung hay không, mà là liệu người ta có thể gán giá trị null cho một đối tượng thuộc loại đó không. Nói cách khác, tôi nghĩ rằng chúng ta nên xác định xem một loại đối tượng là nullable, chứ không phải là Nullable. Sự khác biệt là về ngữ nghĩa, cụ thể là lý do thực tế để xác định tính vô hiệu, thường là tất cả những gì quan trọng.
Trong một hệ thống sử dụng các đối tượng với các loại có thể không xác định cho đến thời gian chạy (dịch vụ web, cuộc gọi từ xa, cơ sở dữ liệu, nguồn cấp dữ liệu, v.v.), một yêu cầu chung là xác định xem null có thể được gán cho đối tượng hay không hoặc liệu đối tượng có thể chứa một con số không Việc thực hiện các hoạt động như vậy trên các loại không có giá trị sẽ có thể tạo ra lỗi, thường là các trường hợp ngoại lệ, rất tốn kém cả về hiệu suất và yêu cầu mã hóa. Để thực hiện phương pháp được ưu tiên cao là chủ động tránh các vấn đề như vậy, cần xác định xem một đối tượng của Loại tùy ý có khả năng chứa null hay không; tức là, cho dù đó là "không thể".
Theo một nghĩa rất thực tế và điển hình, tính vô hiệu trong các thuật ngữ .NET hoàn toàn không ngụ ý rằng Loại của đối tượng là một dạng Nullable. Trong nhiều trường hợp trên thực tế, các đối tượng có các kiểu tham chiếu, có thể chứa giá trị null và do đó tất cả đều là null; không ai trong số này có loại Nullable. Do đó, đối với các mục đích thực tế trong hầu hết các kịch bản, thử nghiệm nên được thực hiện cho khái niệm chung về tính không có giá trị, so với khái niệm phụ thuộc vào việc thực hiện của Nullable. Vì vậy, chúng ta không nên gác máy bằng cách chỉ tập trung vào loại .NET Nullable mà nên kết hợp sự hiểu biết của chúng ta về các yêu cầu và hành vi của nó trong quá trình tập trung vào khái niệm chung, thực tế về tính vô hiệu.