代码之家  ›  专栏  ›  技术社区  ›  Alex Duggleby

如何将System.Type转换为其可为空的版本?

  •  69
  • Alex Duggleby  · 技术社区  · 16 年前

    其中一个问题是:“是否有一种更简单的内置方式来代替我的助手方法?”

    所以从可以为空的类型中获取底层类型很容易,但是如何获取.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
    

    是否有内置方法?

    4 回复  |  直到 7 年前
        1
  •  97
  •   BartoszKP    7 年前

    这是我使用的代码:

    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;
    }
    
        2
  •  14
  •   Mark Jones    13 年前

    我在我的实用程序库中编写了一些我非常依赖的方法。第一种方法是将任何类型转换为其相应的可为空的<类型>形式:

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

    第二个方法只是报告给定类型是否可以为空。此方法由第一个调用,单独使用:

        /// <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实现每次都像一个champ一样工作,但是在最后一行代码中它有点冗长和缓慢。下面的代码体与上面的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;
    

    享受!

    作记号

    P.S.-关于“空性”

    我应该在另一篇文章中重复一个关于空性的声明,它直接适用于正确地解决这个主题。也就是说,我认为这里讨论的重点不应该是如何检查一个对象是否是通用的可以为空的类型,而应该是是否可以为其类型的对象分配一个值为空。换句话说,我认为我们应该确定一个对象类型是否可以为空,而不是它是否可以为空。区别在于语义,即确定空性的实际原因,这通常是最重要的。

    在使用类型可能在运行时未知的对象(Web服务、远程调用、数据库、源等)的系统中,常见的要求是确定是否可以为该对象分配空值,或者该对象是否包含空值。在不可为空的类型上执行此类操作可能会产生错误,通常是异常,这在性能和编码要求方面都非常昂贵。为了采取主动避免此类问题的高度首选方法,有必要确定任意类型的对象是否能够包含空值,即它是否通常是“可空”的。

    在非常实际和典型的意义上,.NET术语中的可空性并不一定意味着对象的类型是可空的形式。实际上,在许多情况下,对象都有引用类型,可以包含空值,因此都可以为空;这些对象都没有可以为空的类型。因此,为了在大多数场景中实现实际目的,应该对可空性的一般概念(而不是与实现相关的可空性概念)进行测试。因此,我们不应该仅仅关注.NET可空类型,而应该在关注可空性的一般、实用概念的过程中,将我们对它的需求和行为的理解结合起来。

        3
  •  9
  •   Thracx    8 年前

    莱曼的回答很好,帮助了我,但是,还有一个问题需要解决。

    Nullable.GetUnderlyingType(type) 只应在类型不是 Nullable 类型。否则,当类型派生自 System.RuntimeType (比如我进去的时候 typeof(System.Int32) )下面的版本避免了调用 可以为空。GetUnderlyingType(类型) 通过检查类型是否为 可空的 相反。

    在下面你会发现一个 ExtensionMethod 此方法的版本,它将立即返回类型 除非 这是一个 ValueType 还没有呢 可空的 .

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

    (很抱歉,我不能简单地在莱曼的回答上发表评论,因为我是新来的,还没有足够的发言权。)

        4
  •  2
  •   vaxquis user2577497    9 年前

    我所知道的没有任何东西 int? 等等,只是句法上的糖分 Nullable<T> 除此之外,不会给予特殊待遇。尤其不太可能,因为您正试图从给定类型的类型信息中获取此信息。通常情况下,这需要一些“滚动您自己的”代码作为给定代码。你必须使用反射来创建一个新的 Nullable 具有输入类型的类型参数的类型。

    编辑: 正如评论所暗示的那样 Nullable<> 经过特殊处理,并在运行时启动,如中所述 this article .