How to check if an object is nullable?

Viewed 116389

How do I check if a given object is nullable in other words how to implement the following method...

bool IsNullableValueType(object o)
{
    ...
}

I am looking for nullable value types. I didn't have reference types in mind.

//Note: This is just a sample. The code has been simplified 
//to fit in a post.

public class BoolContainer
{
    bool? myBool = true;
}

var bc = new BoolContainer();

const BindingFlags bindingFlags = BindingFlags.Public
                        | BindingFlags.NonPublic
                        | BindingFlags.Instance
                        ;


object obj;
object o = (object)bc;

foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
    obj = (object)fieldInfo.GetValue(o);
}

obj now refers to an object of type bool (System.Boolean) with value equal to true. What I really wanted was an object of type Nullable<bool>

So now as a work around I decided to check if o is nullable and create a nullable wrapper around obj.

14 Answers

There are two types of nullable - Nullable<T> and reference-type.

Jon has corrected me that it is hard to get type if boxed, but you can with generics: - so how about below. This is actually testing type T, but using the obj parameter purely for generic type inference (to make it easy to call) - it would work almost identically without the obj param, though.

static bool IsNullable<T>(T obj)
{
    if (obj == null) return true; // obvious
    Type type = typeof(T);
    if (!type.IsValueType) return true; // ref-type
    if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
    return false; // value-type
}

But this won't work so well if you have already boxed the value to an object variable.

Microsoft documentation: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type

The question of "How to check if a type is nullable?" is actually "How to check if a type is Nullable<>?", which can be generalized to "How to check if a type is a constructed type of some generic type?", so that it not only answers the question "Is Nullable<int> a Nullable<>?", but also "Is List<int> a List<>?".

Most of the provided solution use the Nullable.GetUnderlyingType() method, which will obviously only work with the case of Nullable<>. I did not see the general reflective solution that will work with any generic type, so I decided to add it here for posterity, even though this question has already been answered long ago.

To check if a type is some form of Nullable<> using reflection, you first have to convert your constructed generic type, for example Nullable<int>, into the generic type definition, Nullable<>. You can do that by using the GetGenericTypeDefinition() method of the Type class. You can then compare the resulting type to Nullable<>:

Type typeToTest = typeof(Nullable<int>);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true

The same can be applied to any generic type:

Type typeToTest = typeof(List<int>);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true

Several types may seem the same, but a different number of type arguments means it's a completely different type.

Type typeToTest = typeof(Action<DateTime, float>);
bool isAction1 = typeToTest.GetGenericTypeDefinition() == typeof(Action<>);
bool isAction2 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,>);
bool isAction3 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,,>);
// isAction1 == false
// isAction2 == true
// isAction3 == false

Since Type object are instantiated once per type, you can check for reference equality between them. So if you want to check if two objects are of the same generic type definition, you can write:

var listOfInts = new List<int>();
var listOfStrings = new List<string>();

bool areSameGenericType =
    listOfInts.GetType().GetGenericTypeDefinition() ==
    listOfStrings.GetType().GetGenericTypeDefinition();
// areSameGenericType == true

If you'd like to check if an object is nullable, rather than a Type, then you can use the above technique together with Marc Gravell's solution to create a rather simple method:

static bool IsNullable<T>(T obj)
{
    if (!typeof(T).IsGenericType)
        return false;

    return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}

Well, you could use:

return !(o is ValueType);

... but an object itself isn't nullable or otherwise - a type is. How were you planning on using this?

The simplest way I can figure out is:

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}

Be carefull, when boxing a nullable type (Nullable<int> or int? for instance) :

int? nullValue = null;
object boxedNullValue = (object)nullValue;
Debug.Assert(boxedNullValue == null);

int? value = 10;
object boxedValue = (object)value;
Debug.Assert( boxedValue.GetType() == typeof(int))

It becomes a true reference type, so you lose the fact it was nullable.

I think the ones using Microsoft's suggested testing against IsGenericType are good, but in the code for GetUnderlyingType, Microsoft uses an additional test to make sure you didn't pass in the generic type definition Nullable<>:

 public static bool IsNullableType(this Type nullableType) =>
    // instantiated generic type only                
    nullableType.IsGenericType &&
    !nullableType.IsGenericTypeDefinition &&
    Object.ReferenceEquals(nullableType.GetGenericTypeDefinition(), typeof(Nullable<>));
Related