【问题标题】:How do I convert a System.Type to its nullable version?如何将 System.Type 转换为其可为空的版本?
【发布时间】:2008-09-20 13:08:11
【问题描述】:

再说一次:“有没有一种更简单的内置方法来代替我的辅助方法?”

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

有内置方法吗?

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    这是我使用的代码:

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

    【讨论】:

    • 不错!这是一个非常巧妙的解决方案。
    • 很好的答案!正是我想要的。
    • 请注意,如果类型不可为空,Nullable.GetUnderlyingType 将返回 null,因此您需要进行检查。
    • @AmitG 你是对的。当我将值类型传递给这个函数时,我遇到了null 错误。
    • 正如@AmitG 所说,在访问IsValueType 属性之前,您确实需要确保type 不为空。 -1 直到修复
    【解决方案2】:

    我在实用程序库中编写了几个方法,我非常依赖这些方法。第一个是将任何 Type 转换为其对应的 Nullable 形式的方法:

        /// <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 实现每次都像冠军一样工作,但在最后一行代码中它有点冗长和缓慢。 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;
    

    享受吧!

    标记

    附: - 关于“可空性”

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

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

    在非常实际和典型的意义上,.NET 术语中的可空性并不一定意味着对象的类型是可空的形式。事实上,在很多情况下,对象都有引用类型,可以包含空值,因此都是可以为空的;这些都没有 Nullable 类型。因此,在大多数情况下,出于实际目的,应针对可空性的一般概念进行测试,而不是可空性的依赖于实现的概念。因此,我们不应仅仅关注 .NET Nullable 类型,而是将我们对其要求和行为的理解融入到可空性的一般实用概念的过程中。

    【讨论】:

      【解决方案3】:

      Lyman 的回答很好,对我有所帮助,但是,还有一个错误需要修复。

      Nullable.GetUnderlyingType(type) 应该只在类型不是Nullable 类型时才被调用。否则,当类型派生自 System.RuntimeType 时(例如当我传入 typeof(System.Int32) 时),它似乎错误地返回 null 。以下版本通过检查类型是否为Nullable 来避免调用Nullable.GetUnderlyingType(type)

      您将在下面找到此方法的 ExtensionMethod 版本,它将立即返回类型除非它是 ValueType 而不是 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);
      }
      

      (对不起,我不能简单地对莱曼的回答发表评论,因为我是新手,还没有足够的代表。)

      【讨论】:

        【解决方案4】:

        据我所知,没有任何内置的东西,因为int? 等只是Nullable&lt;T&gt; 的语法糖;并且除此之外没有给予特殊待遇。鉴于您试图从给定类型的类型信息中获取此信息,这尤其不可能。通常,这总是需要一些“滚动你自己的”代码作为给定的。您必须使用反射来创建一个新的 Nullable 类型,其类型参数为输入类型。

        编辑: 正如 cmets 建议的那样,实际上 Nullable&lt;&gt; 被特殊处理,并在运行时启动,如 this article 中所述。

        【讨论】:

        • 实际上,我很确定 CLR 在处理 Nullable 方面有一些特殊的魔力。我需要检查一下。
        • 我会对此感兴趣,如果是这样,我很高兴承认我错了:-)
        • 由于您可以通过+ 运算符添加两个int?,我们知道 Nullables 得到特殊处理,因为这种泛型运算符重载不会否则工作。
        猜你喜欢
        • 1970-01-01
        • 2010-09-10
        • 2016-04-04
        • 2022-06-15
        • 2014-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-31
        相关资源
        最近更新 更多