Как преобразовать систему.Введите его версию с нулевым значением?


еще раз один из тех: "есть ли более простой встроенный способ делать вещи вместо моего вспомогательного метода?"

таким образом, легко получить базовый тип из типа nullable, но как я могу получить nullable версию типа .NET?

у меня есть

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

и я хочу!--4-->

int? 
DateTime?

или

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

есть ли встроенный способ?

4 69

4 ответа:

вот код, который я использую:

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

у меня есть несколько методов, которые я написал в своей библиотеке утилит, на которые я сильно полагался. Первый-это метод, который преобразует любой тип в соответствующую ему форму 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;
    }

второй метод просто сообщает, Является ли данный тип 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<>);
    }

выше 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;

наслаждайтесь!

Марк

P. S. - О "допустимость значения"

Я должен повторить заявление о недействительности, которое я сделал в отдельном посте, которое относится непосредственно к правильному решению этой темы. То есть, я считаю, что в центре внимания обсуждения здесь не должно быть, как проверить, является ли объект общим типом Nullable, а можно ли присвоить значение null на объект своего типа. Другими словами, Я думаю, что мы должны определить, является ли тип объекта nullable, а не является ли он Nullable. Разница заключается в семантике, а именно в практических причинах определения недействительности, что обычно имеет значение.

в системе, использующей объекты с типами, возможно неизвестными до времени выполнения (веб-службы, удаленные вызовы, базы данных, каналы и т. д.), общим требованием является определение того, является ли объекту можно присвоить значение null или указать, может ли объект содержать значение null. Выполнение таких операций с ненулевыми типами, скорее всего, приведет к ошибкам, обычно исключениям, которые очень дороги как с точки зрения производительности, так и с точки зрения требований к кодированию. Для того, чтобы принять весьма предпочтительный подход упреждающего избежания таких проблем, необходимо определить, способен ли объект произвольного типа содержать нуль; т. е., является ли он вообще "нулевым".

In очень практичный и типичный смысл, nullability в терминах .NET вовсе не обязательно означает, что тип объекта является формой Nullable. Во многих случаях на самом деле объекты имеют ссылочные типы, могут содержать нулевое значение и, таким образом, все они имеют нулевой тип; ни один из них не имеет нулевого типа. Поэтому для практических целей в большинстве сценариев тестирование должно проводиться для общей концепции nullability, а не для концепции Nullable, зависящей от реализации. Так что нам не стоит зацикливаться на фокусировке исключительно на .Чистый тип, допускающий значение null, но скорее включайте наше понимание его требований и поведения в процессе сосредоточения внимания на общие, практические концепции допустимость значений null.

ответ Лаймана велик и помог мне, однако, есть еще одна ошибка, которая должна быть исправлена.

Nullable.GetUnderlyingType(type) следует вызывать только в том случае, если тип еще не является Nullable тип. В противном случае он, похоже, ошибочно возвращает null, когда тип является производным от System.RuntimeType (например, когда я прохожу в typeof(System.Int32)). Ниже версия позволяет избежать необходимости вызова Nullable.GetUnderlyingType(type) проверить, если тип Nullable вместо.

ниже вы найдете 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);
}

(извините, но я не мог просто оставить комментарий к ответу Лаймана, потому что я был новичком и еще не имел достаточно репутации.)

там нет ничего встроенного, что я знаю, как int? и т. д. это просто синтаксический сахар для Nullable<T>; и не получает специального лечения за пределами этого. Это особенно маловероятно, учитывая, что вы пытаетесь получить от информации о типе данного типа. Как правило, это всегда требует некоторого "свернуть свой собственный" код как данность. Вам придется использовать отражение, чтобы создать новый Nullable тип с параметром типа входного типа.

Edit: как комментарии предлагают на самом деле Nullable<>и специально обработанная, и во время выполнения для загрузки, как описано в в этой статье.