2008-09-20 30 views
65

Một lần nữa một trong những điều sau: "Có cách nào dễ dàng hơn để làm những việc thay vì phương pháp trợ giúp của tôi không?"Làm cách nào để chuyển đổi một System.Type thành phiên bản có thể vô hiệu hóa?

Vì vậy, thật dễ dàng để có được loại cơ bản từ một loại nullable, nhưng làm thế nào để tôi có được phiên bản nullable của một loại .NET?

Vì vậy, tôi có

typeof(int) 
typeof(DateTime) 
System.Type t = something; 

và tôi muốn

int? 
DateTime? 

hoặc

Nullable<int> (which is the same) 
if (t is primitive) then Nullable<T> else just T 

Có một phương pháp tích hợp?

Trả lời

91

Đây là mã tôi sử dụng:

Type GetNullableType(Type type) { 
    // Use Nullable.GetUnderlyingType() to remove the Nullable<T> wrapper if type is already nullable. 
    type = Nullable.GetUnderlyingType(type); 
    if (type.IsValueType) 
     return typeof(Nullable<>).MakeGenericType(type); 
    else 
     return type; 
} 
+0

Tốt! Đây là một giải pháp thực sự gọn gàng. – ljs

+0

Câu trả lời hay! Chỉ cần những gì tôi đang tìm kiếm. –

+0

Giải pháp mát. Điều gì về làm cho nó một phương pháp mở rộng trên Type chính nó? Có vẻ phù hợp trong tình huống này. –

2

Không có bất cứ điều gì được xây dựng trong mà tôi biết, như int?, vv là đường chỉ là cú pháp cho Nullable<T>; và không được điều trị đặc biệt ngoài điều đó. Nó đặc biệt không được cho bạn đang cố gắng để có được điều này từ các loại thông tin của một loại nhất định. Thông thường, luôn luôn yêu cầu một số mã 'cuộn mã của riêng bạn' như một mã đã cho. Bạn sẽ phải sử dụng Reflection để tạo kiểu Nullable mới với tham số kiểu của kiểu đầu vào.

Edit: Theo các ý kiến ​​đề nghị thực sự Nullable<> đối xử đặc biệt, và trong thời gian chạy để khởi động như được giải thích trong this article.

+0

Actaully, tôi khá chắc chắn CLR có một số phép thuật đặc biệt để xử lý Nullable <> 's hơi khác nhau. Tôi sẽ cần phải kiểm tra này. – TraumaPony

+0

Tôi sẽ quan tâm đến điều này, vui lòng thừa nhận tôi sai nếu đó là trường hợp :-) – ljs

+0

CLR không có xử lý đặc biệt cho Nullables. http://blogs.msdn.com/somasegar/archive/2005/08/11/450640.aspx –

7

Câu trả lời của Lyman rất tuyệt và đã giúp tôi, tuy nhiên, có thêm một lỗi cần phải sửa.

Nullable.GetUnderlyingType(type) chỉ nên được gọi là iff loại không phải là loại Nullable. Nếu không, có vẻ như trả về lỗi không đúng khi loại có nguồn gốc từ System.RuntimeType (chẳng hạn như khi tôi vượt qua trong typeof(System.Int32)). Phiên bản dưới đây không cần phải gọi số Nullable.GetUnderlyingType(type) bằng cách kiểm tra xem loại đó có phải là Nullable thay thế không.

Dưới đây bạn sẽ tìm thấy một phiên bản ExtensionMethod của phương pháp này mà ngay lập tức sẽ trở lại loại trừ đó là một ValueType đó là chưa Nullable.

Type NullableVersion(this Type sourceType) 
{ 
    if(sourceType == null) 
    { 
     // Throw System.ArgumentNullException or return null, your preference 
    } 
    else if(sourceType == typeof(void)) 
    { // Special Handling - known cases where Exceptions would be thrown 
     return null; // There is no Nullable version of void 
    } 

    return !sourceType.IsValueType 
      || (sourceType.IsGenericType 
       && sourceType.GetGenericTypeDefinition() == typeof(Nullable<>)) 
     ? sourceType 
     : typeof(Nullable<>).MakeGenericType(sourceType); 
} 

(Tôi xin lỗi, nhưng tôi không thể chỉ đơn giản là viết bình luận cho câu trả lời Lyman vì tôi là mới và không có đủ đại diện nào.)

14

Tôi có một vài phương pháp tôi đã viết trong thư viện tiện ích của tôi mà tôi đã dựa nhiều vào. Đầu tiên là một phương pháp có thể chuyển đổi bất kỳ loại để Nullable < Loại hình thức > tương ứng của nó:

/// <summary> 
    /// [ <c>public static Type GetNullableType(Type TypeToConvert)</c> ] 
    /// <para></para> 
    /// Convert any Type to its Nullable&lt;T&gt; form, if possible 
    /// </summary> 
    /// <param name="TypeToConvert">The Type to convert</param> 
    /// <returns> 
    /// The Nullable&lt;T&gt; converted from the original type, the original type if it was already nullable, or null 
    /// if either <paramref name="TypeToConvert"/> could not be converted or if it was null. 
    /// </returns> 
    /// <remarks> 
    /// To qualify to be converted to a nullable form, <paramref name="TypeToConvert"/> must contain a non-nullable value 
    /// type other than System.Void. Otherwise, this method will return a null. 
    /// </remarks> 
    /// <seealso cref="Nullable&lt;T&gt;"/> 
    public static Type GetNullableType(Type TypeToConvert) 
    { 
     // Abort if no type supplied 
     if (TypeToConvert == null) 
      return null; 

     // If the given type is already nullable, just return it 
     if (IsTypeNullable(TypeToConvert)) 
      return TypeToConvert; 

     // If the type is a ValueType and is not System.Void, convert it to a Nullable<Type> 
     if (TypeToConvert.IsValueType && TypeToConvert != typeof(void)) 
      return typeof(Nullable<>).MakeGenericType(TypeToConvert); 

     // Done - no conversion 
     return null; 
    } 

Phương pháp thứ hai chỉ đơn giản là báo cáo cho dù một loại nhất định là nullable.Phương pháp này được gọi bởi người đầu tiên và rất hữu ích riêng:

/// <summary> 
    /// [ <c>public static bool IsTypeNullable(Type TypeToTest)</c> ] 
    /// <para></para> 
    /// Reports whether a given Type is nullable (Nullable&lt; Type &gt;) 
    /// </summary> 
    /// <param name="TypeToTest">The Type to test</param> 
    /// <returns> 
    /// true = The given Type is a Nullable&lt; Type &gt;; false = The type is not nullable, or <paramref name="TypeToTest"/> 
    /// is null. 
    /// </returns> 
    /// <remarks> 
    /// This method tests <paramref name="TypeToTest"/> and reports whether it is nullable (i.e. whether it is either a 
    /// reference type or a form of the generic Nullable&lt; T &gt; type). 
    /// </remarks> 
    /// <seealso cref="GetNullableType"/> 
    public static bool IsTypeNullable(Type TypeToTest) 
    { 
     // Abort if no type supplied 
     if (TypeToTest == null) 
      return false; 

     // If this is not a value type, it is a reference type, so it is automatically nullable 
     // (NOTE: All forms of Nullable<T> are value types) 
     if (!TypeToTest.IsValueType) 
      return true; 

     // Report whether TypeToTest is a form of the Nullable<> type 
     return TypeToTest.IsGenericType && TypeToTest.GetGenericTypeDefinition() == typeof(Nullable<>); 
    } 

Trên đây IsTypeNullable thực hiện hoạt động như một nhà vô địch mọi thời gian, nhưng nó hơi dài dòng và chậm chạp trong dòng mã cuối cùng của nó. Phần mã sau giống như trên cho IsTypeNullable, ngoại trừ dòng mã cuối cùng đơn giản và nhanh hơn:

 // Abort if no type supplied 
     if (TypeToTest == null) 
      return false; 

     // If this is not a value type, it is a reference type, so it is automatically nullable 
     // (NOTE: All forms of Nullable<T> are value types) 
     if (!TypeToTest.IsValueType) 
      return true; 

     // Report whether an underlying Type exists (if it does, TypeToTest is a nullable Type) 
     return Nullable.GetUnderlyingType(TypeToTest) != null; 

Tận hưởng!

Đánh dấu

P.S. - Giới thiệu về "vô hiệu"

Tôi nên lặp lại một tuyên bố về tính không có khả năng mà tôi đã thực hiện trong một bài đăng riêng biệt, áp dụng trực tiếp cho việc 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à cách kiểm tra xem một đối tượng có phải là một kiểu Nullable chung hay không, mà là người ta có thể gán một giá trị null cho một đối tượng thuộc kiểu của nó. 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, không cho dù đó là Nullable. Sự khác biệt là trong ngữ nghĩa, cụ thể là những lý do thực tế để xác định tính vô dụng, mà 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 kiểu có thể chưa biết cho đến khi 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.), yêu cầu chung là xác định xem có thể gán một giá trị null cho đối tượng hay không đối tượng có thể chứa một giá trị rỗng. Việc thực hiện các hoạt động như vậy đối với các kiểu không nullable có thể sẽ tạo ra các lỗi, thường là các ngoại lệ, rất tốn kém cả về các yêu cầu về hiệu suất và mã hóa. Để có cách tiếp cận được ưu tiên cao của chủ động tránh các vấn đề như vậy, cần xác định xem một đối tượng của một loại tùy ý có khả năng chứa một giá trị rỗng không; tức là, cho dù nó nói chung là 'vô giá trị'.

Trong một ý nghĩa rất thực tế và điển hình, tính không có trong thuật ngữ .NET không nhất thiết phải ngụ ý rằng Kiểu 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 một giá trị null, và do đó tất cả đều không có giá trị; không cái nào trong số này có kiểu Nullable. Do đó, cho các mục đích thực tế trong hầu hết các kịch bản, việc thử nghiệm nên được thực hiện cho khái niệm chung về tính vô hiệu, so với khái niệm phụ thuộc vào thực thi của Nullable. Vì vậy, chúng ta không nên bị treo lên bằng cách chỉ tập trung vào loại .NET Nullable mà là 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 thực tế về tính vô dụng.

Các vấn đề liên quan