У меня есть пара методов, которые я написал в своей служебной библиотеке, на которые я сильно полагался. Первый - это метод, который преобразует любой тип в соответствующую ему 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;
Наслаждайтесь!
Mark
P.S. - про "обнуляемость"
Я должен повторить заявление об обнуляемости, которое я сделал в отдельном посте, который относится непосредственно к правильному решению этой темы. То есть, я полагаю, что основное внимание здесь должно быть сосредоточено не на том, как проверить, является ли объект универсальным типом Nullable, а на том, можно ли присвоить значение null объекту его типа. Другими словами, я думаю, что мы должны определить, является ли тип объекта обнуляемым, а не обнуляемым. Разница заключается в семантике, а именно в практических причинах определения обнуляемости, которая, как правило, имеет значение.
В системе, использующей объекты с типами, которые, возможно, неизвестны до времени выполнения (веб-службы, удаленные вызовы, базы данных, каналы и т. Д.), Общим требованием является определение, можно ли присвоить объекту нулевое значение, или объект может содержать ноль. Выполнение таких операций над ненулевыми типами может привести к ошибкам, обычно исключениям, которые очень дороги как с точки зрения производительности, так и требований к кодированию. Чтобы принять чрезвычайно предпочтительный подход к упреждающему избеганию таких проблем, необходимо определить, способен ли объект произвольного типа содержать нуль; то есть, является ли это вообще 'обнуляемым'.
В очень практичном и типичном смысле обнуляемость в терминах .NET вовсе не обязательно означает, что тип объекта является формой обнуляемого значения. Фактически, во многих случаях объекты имеют ссылочные типы, могут содержать нулевое значение и, следовательно, могут иметь значение NULL; ни один из них не имеет типа Nullable. Таким образом, для практических целей в большинстве сценариев, тестирование должно быть сделано для общей концепции обнуляемости, в отличие от концепции Nullable, зависящей от реализации. Поэтому мы не должны зацикливаться на том, чтобы сосредоточиться исключительно на типе .NET Nullable, а должны включить наше понимание его требований и поведения в процесс сосредоточения внимания на общей практической концепции обнуляемости.