Как мне преобразовать System.Type в его версию с нулевым значением?
Еще раз один из них: "Есть ли более простой встроенный способ делать вещи вместо моего вспомогательного метода?"
Таким образом, легко получить базовый тип из обнуляемого типа, но как мне получить обнуляемую версию типа.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 ответа
Вот код, который я использую:
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
/// <summary>
/// [ <c>public static Type GetNullableType(Type TypeToConvert)</c> ]
/// <para></para>
/// Convert any Type to its Nullable<T> form, if possible
/// </summary>
/// <param name="TypeToConvert">The Type to convert</param>
/// <returns>
/// The Nullable<T> 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<T>"/>
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< Type >)
/// </summary>
/// <param name="TypeToTest">The Type to test</param>
/// <returns>
/// true = The given Type is a Nullable< Type >; 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< T > 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 объекту его типа. Другими словами, я думаю, что мы должны определить, является ли тип объекта обнуляемым, а не обнуляемым. Разница заключается в семантике, а именно в практических причинах определения обнуляемости, которая обычно имеет значение.
В системе, использующей объекты с типами, которые могут быть неизвестны до времени выполнения (веб-службы, удаленные вызовы, базы данных, каналы и т. Д.), Общим требованием является определение того, можно ли присвоить объекту нулевое значение или объект может содержать ноль. Выполнение таких операций над ненулевыми типами, вероятно, приведет к ошибкам, обычно исключениям, которые очень дороги как с точки зрения производительности, так и требований к кодированию. Чтобы принять чрезвычайно предпочтительный подход к упреждающему избеганию таких проблем, необходимо определить, способен ли объект произвольного типа содержать нуль; то есть, является ли это вообще 'обнуляемым'.
В очень практичном и типичном смысле обнуляемость в терминах.NET вовсе не обязательно означает, что тип объекта является формой обнуляемости. Фактически, во многих случаях объекты имеют ссылочные типы, могут содержать нулевое значение и, следовательно, могут иметь значение NULL; ни один из них не имеет типа Nullable. Поэтому для практических целей в большинстве сценариев следует проводить тестирование для общей концепции обнуляемости, в отличие от концепции Nullable, зависящей от реализации. Поэтому мы не должны зацикливаться на том, чтобы сосредоточиться исключительно на типе.NET Nullable, а должны включить наше понимание его требований и поведения в процесс сосредоточения внимания на общей практической концепции обнуляемости.
Ответ Лаймана великолепен и помог мне, однако есть еще одна ошибка, которую нужно исправить.
Nullable.GetUnderlyingType(type)
должен вызываться только тогда, когда тип еще не Nullable
тип. В противном случае кажется, что он ошибочно возвращает ноль, когда тип наследуется от 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>
; и не получает особого отношения к этому. Это особенно маловероятно, учитывая, что вы пытаетесь получить это из информации о типе данного типа. Как правило, это всегда требует некоторого "накатить свой" код как данность. Вы должны использовать Reflection для создания нового Nullable
тип с параметром типа типа ввода.
Изменить: как комментарии предлагают на самом деле Nullable<>
обрабатывается специально, и во время выполнения загружается, как описано в этой статье.