簡體   English   中英

如何將System.Type轉換為其可為空的版本?

[英]How do I convert a System.Type to its nullable version?

再說一遍:“是否有一種比我的助手方法更簡單的內置處理方式?”

因此從可為空的類型中獲取基礎類型很容易,但是如何獲取.NET類型的可為空的版本呢?

所以我有

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

而且我要

int? 
DateTime?

要么

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

有內置方法嗎?

這是我使用的代碼:

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

我已經在實用程序庫中編寫了一些我非常依賴的方法。 第一種是將任何Type轉換為其對應的Nullable <Type>形式的方法:

    /// <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;
    }

第二種方法只是報告給定的Type是否可為空。 此方法由第一個調用,並且分別有用:

    /// <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<>);
    }

上面的IsTypeNullable實現每次都像冠軍一樣工作,但是在最后一行代碼中有些冗長和緩慢。 以下代碼主體與上面的IsTypeNullable相同,但最后一行代碼更簡單,更快捷:

        // 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;

請享用!

標記

PS-關於“可空性”

我應該在另一篇文章中重復有關可空性的聲明,該聲明直接適用於正確解決此主題。 也就是說,我認為這里的討論重點不應是如何檢查對象是否為通用Nullable類型,而是應該是否可以為該類型的對象分配null值。 換句話說,我認為我們應該確定對象類型是否可為空,而不是它是否可為空。 區別在於語義,即確定可為空性的實際原因,通常這很重要。

在使用對象的類型直到運行時可能未知的系統(Web服務,遠程調用,數據庫,提要等)中,一個共同的要求是確定是否可以為該對象分配空值,或者該對象是否可能包含空值。 對非空類型執行此類操作可能會產生錯誤,通常是異常,這在性能和編碼要求方面都非常昂貴。 為了采取主動避免此類問題的首選方法,有必要確定任意類型的對象是否能夠包含null。 即,它通常是否為“可為空”。

從非常實際和典型的意義上講,.NET術語中的可為空性不一定表示對象的類型是可為空的形式。 實際上,在許多情況下,對象具有引用類型,可以包含空值,因此都可以為空。 這些都沒有Nullable類型。 因此,出於實用目的,在大多數情況下,應該針對可空性的一般概念進行測試,而不是依賴於實現的可空性概念。 因此,我們不應該只專注於.NET Nullable類型,而應該在專注於通用性,實用性的可空性概念的過程中結合我們對它的要求和行為的理解。

Lyman的回答很好,對我有所幫助,但是,還有一個錯誤需要修復。

僅當類型尚未為Nullable類型時,才應調用Nullable.GetUnderlyingType(type) 否則,當類型派生自System.RuntimeType (例如,當我傳入typeof(System.Int32) ),它似乎錯誤地返回了null。 下面的版本通過檢查類型是否為Nullable來避免調用Nullable.GetUnderlyingType(type)

在下面,您將找到此方法的ExtensionMethod版本,該版本將立即返回類型, 除非它是尚未為NullableValueType

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);
}

(對不起,但是我不能簡單地在萊曼的答案中發表評論,因為我是新來的,並且沒有足夠的代表。)

我不知道內置什么內容,例如int? 等只是Nullable<T>語法糖; 並且沒有得到特別的待遇。 鑒於您嘗試從給定類型的類型信息中獲取此信息,這種情況尤其不可能發生。 通常,這總是需要一定的“滾動自己的”代碼。 您將必須使用Reflection創建帶有輸入類型的type參數的新Nullable類型。

編輯:正如評論所建議的,實際上Nullable<> 特殊對待,並在運行時按照本文中的說明進行引導。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM