E ective usage of underlying Nullable C# with Example
argument Any nullable type is a generic type. And any nullable type is a value type. There are some tricks which allow to effectively use the result of the Nullable.GetUnderlyingType method when creating code related to reflection/code-generation purposes: public static class TypesHelper { public static bool IsNullable(this Type type) { Type underlyingType; return IsNullable(type, out underlyingType); } public static bool IsNullable(this Type type, out Type underlyingType) { underlyingType = Nullable.GetUnderlyingType(type); return underlyingType != null; } public static Type GetNullable(Type type) { Type underlyingType; return IsNullable(type, out underlyingType) ? type : NullableTypesCache.Get(type); } public static bool IsExactOrNullable(this Type type, Func predicate) { Type underlyingType; if(IsNullable(type, out underlyingType)) return IsExactOrNullable(underlyingType, predicate); return predicate(type); } public static bool IsExactOrNullable(this Type type) where T : struct { return IsExactOrNullable(type, t => Equals(t, typeof(T))); } } The usage: Type type = typeof(int).GetNullable(); Console.WriteLine(type.ToString()); if(type.IsNullable()) Console.WriteLine("Type is nullable."); Type underlyingType; if(type.IsNullable(out underlyingType)) Console.WriteLine("The underlying type is " + underlyingType.Name + "."); if(type.IsExactOrNullable()) Console.WriteLine("Type is either exact or nullable Int32."); if(!type.IsExactOrNullable(t => t.IsEnum)) Console.WriteLine("Type is neither exact nor nullable enum."); Output: System.Nullable`1[System.Int32] Type is nullable. The underlying type is Int32. Type is either exact or nullable Int32. Type is neither exact nor nullable enum. PS. The NullableTypesCache is defined as follows: static class NullableTypesCache { readonly static ConcurrentDictionary cache = new ConcurrentDictionary(); static NullableTypesCache() { cache.TryAdd(typeof(byte), typeof(Nullable)); cache.TryAdd(typeof(short), typeof(Nullable)); cache.TryAdd(typeof(int), typeof(Nullable)); cache.TryAdd(typeof(long), typeof(Nullable)); cache.TryAdd(typeof(float), typeof(Nullable)); cache.TryAdd(typeof(double), typeof(Nullable)); cache.TryAdd(typeof(decimal), typeof(Nullable)); cache.TryAdd(typeof(sbyte), typeof(Nullable)); cache.TryAdd(typeof(ushort), typeof(Nullable)); cache.TryAdd(typeof(uint), typeof(Nullable)); cache.TryAdd(typeof(ulong), typeof(Nullable)); //... } readonly static Type NullableBase = typeof(Nullable<>); internal static Type Get(Type type) { // Try to avoid the expensive MakeGenericType method call return cache.GetOrAdd(type, t => NullableBase.MakeGenericType(t)); } }