Programing

System.Type을 nullable 버전으로 어떻게 변환합니까?

lottogame 2020. 10. 27. 07:49
반응형

System.Type을 nullable 버전으로 어떻게 변환합니까?


다시 한 번 그 중 하나 : "내 도우미 메서드 대신 작업을 수행하는 더 쉬운 기본 제공 방법이 있습니까?"

따라서 nullable 형식에서 기본 형식을 얻는 것은 쉽지만 .NET 형식의 nullable 버전을 얻으려면 어떻게해야합니까?

그래서 나는 가지고있다

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이 nullable인지 여부를보고합니다. 이 메서드는 첫 번째 메서드에 의해 호출되며 별도로 유용합니다.

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

The above IsTypeNullable implementation works like a champ every time, but it's slightly verbose and slow in its last code line. The following code body is the same as above for IsTypeNullable, except the last code line is simpler and faster:

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

Enjoy!

Mark

P.S. - About "nullability"

I should repeat a statement about nullability I made in a separate post, which applies directly to properly addressing this topic. That is, I believe the focus of the discussion here should not be how to check to see if an object is a generic Nullable type, but rather whether one can assign a value of null to an object of its type. In other words, I think we should be determining whether an object type is nullable, not whether it is Nullable. The difference is in semantics, namely the practical reasons for determining nullability, which is usually all that matters.

In a system using objects with types possibly unknown until run-time (web services, remote calls, databases, feeds, etc.), a common requirement is to determine whether a null can be assigned to the object, or whether the object might contain a null. Performing such operations on non-nullable types will likely produce errors, usually exceptions, which are very expensive both in terms of performance and coding requirements. To take the highly-preferred approach of proactively avoiding such problems, it is necessary to determine whether an object of an arbitrary Type is capable of containing a null; i.e., whether it is generally 'nullable'.

In a very practical and typical sense, nullability in .NET terms does not at all necessarily imply that an object's Type is a form of Nullable. In many cases in fact, objects have reference types, can contain a null value, and thus are all nullable; none of these have a Nullable type. Therefore, for practical purposes in most scenarios, testing should be done for the general concept of nullability, vs. the implementation-dependent concept of Nullable. So we should not be hung up by focusing solely on the .NET Nullable type but rather incorporate our understanding of its requirements and behavior in the process of focusing on the general, practical concept of nullability.


Lyman's answer is great and has helped me, however, there's one more bug which needs to be fixed.

Nullable.GetUnderlyingType(type) should only be called iff the type isn't already a Nullable type. Otherwise, it seems to erroneously return null when the type derives from System.RuntimeType (such as when I pass in typeof(System.Int32) ). The below version avoids needing to call Nullable.GetUnderlyingType(type) by checking if the type is Nullable instead.

Below you'll find an ExtensionMethod version of this method which will immediately return the type unless it's a ValueType that's not already 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);
}

(I'm sorry, but I couldn't simply post a comment to Lyman's answer because I was new and didn't have enough rep yet.)


There isn't anything built in that I know of, as the int?, etc. is just syntactic sugar for Nullable<T>; and isn't given special treatment beyond that. It's especially unlikely given you're attempting to obtain this from the type information of a given type. Typically that always necessitates some 'roll your own' code as a given. You would have to use Reflection to create a new Nullable type with type parameter of the input type.

Edit: As the comments suggest actually Nullable<> is treated specially, and in the runtime to boot as explained in this article.

참고URL : https://stackoverflow.com/questions/108104/how-do-i-convert-a-system-type-to-its-nullable-version

반응형