232

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.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Sandeep Datta
  • 28,607
  • 15
  • 70
  • 90
  • Should the code include strings as being nullable? They are a non-generic ValueType which appears to be nullable. Or are they not a ValueType? – TamusJRoyce May 02 '12 at 21:23
  • 1
    String is not a ValueType. It is a Reference type. – Suncat2000 Mar 22 '13 at 13:09
  • This is a really good question! The 'Type.IsNullableType()' is kind of deceiving because it actually only checks for the type being a 'Nullable', which didn't return expected results if you actually wanted to check for any types that can accept a null value (e.g. I tried to use with a.IsNullableType(), where 'a' was a 'typeof(string)' determined at runtime) – ErrCode Nov 07 '18 at 08:35
  • Answer is in fieldInfo.FieldType: check if FieldType is generic and generic type is of Nullable<> type. (Example: if (FieldType.IsGenericType && FieldType.GetGenericTypeDefinition() == typeof(Nullable<>))). Do not try to get obj.GetType() it will have UndelyingSystemType of Nullable variable T (in your case of Boolean type, instead of Nullable), it's a boxing problem. – SoLaR Aug 21 '19 at 08:46

14 Answers14

310

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://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type

zendu
  • 1,108
  • 1
  • 14
  • 36
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 7
    The last line is only valid if you somehow manage to get a boxed Nullable instead of boxing straight to T. It's possible, but tricky to achieve from what I remember. – Jon Skeet Dec 17 '08 at 14:22
  • This code was helpful for me, not because I got a boxed Nullable but because I was writing a generic WPF converter base class and some properties are nullable, so I used Nullable.GetUnderlyingType to detect that case and Activator.CreateInstance to make a boxed nullable, (Convert.ChangeType doesn't handle nullables btw). – Qwertie Jun 09 '11 at 17:43
  • Every non-valuetype is nullable? Maybe I misunderstand the answer, but I actually think that when it is a reference type, result must be false. I'll update the answer if no-one objects. – Abel Mar 10 '12 at 23:41
  • @Abel yes, pretty-much every non value-type is nullable - or more accurately, every reference type can be assigned null - meaning: classes, interfaces, delegates etc. If you mean unmanaged pointers, then ... well, that's a different game entirely. – Marc Gravell Mar 10 '12 at 23:54
  • 1
    @Abel if you mean re his edit to clarify that he hadn't considered reference types, I *think* my answer predated that edit; the reader can make their own decision there, based on their own needs, I suspect (confirmed: his comment re ref-types as added at 14:42; my answer was all <= 14:34) – Marc Gravell Mar 10 '12 at 23:56
  • I had "nullable" and "is Nullable" mixed in my head. Of course every ref type is nullable (in the meaning: can be assigned/contain null). I read the method IsNullable as AssignableToNullable (i.e. `var x = (Nullable) obj` wouldn't throw) . Which is not the same. – Abel Mar 11 '12 at 16:29
  • 1
    Will (obj == null) throw an exception when obj = 1 ? – Qi Fan Mar 27 '12 at 22:14
  • @QiFan no, why would it? It will just be false. – Marc Gravell Mar 27 '12 at 22:42
  • `obj == null` will throw an exception if you have a `where T : struct` constraint. If I know it's a struct, and just want to know if it's a `Nullable<>`, would `Nullable.GetUnderlyingType(type) != null` be sufficient? Is there any other way to find out? `typeof(T).IsAssignableFrom(typeof(Nullable<>))` doesn't seem to work. – Justin Morgan - On strike Nov 09 '12 at 20:03
  • @Justin Nullable GetUnderlyingType with typeof(T) should work – Marc Gravell Nov 09 '12 at 20:07
  • 3
    @JustinMorgan If `T` is a generic parameter constrained by `T : struct`, then `T` is not allowed to be `Nullable<>`, so you need no check in that case! I know the type `Nullable<>` is a struct, but in C# the constraint `where T : struct` specifically exclude nullable value-types. The spec says: _"Note that although classified as a value type, a nullable type (§4.1.10) does not satisfy the value type constraint."_ – Jeppe Stig Nielsen Dec 03 '12 at 14:07
  • Answerer: Is your method meant to check if the **compile-time type** is nullable? Because that's easy to see with intellisense. The **run-time** type is not nullable if you box a nullable struct. For example, using your method, what does `IsNullable(new Nullable(5))` return? What does `IsNullable(5)` return? – Jeppe Stig Nielsen Dec 03 '12 at 14:32
  • i think your "obvious" clause should say ReferenceEquals(obj,null) , just to be safe – smartcaveman May 05 '13 at 07:26
  • @smartcaveman no need; generics doesn't have support for operators, so that will always be an unbox_any plus reference check – Marc Gravell May 05 '13 at 08:19
  • @MarcGravell - so even if the particular T has an ==(T whatever, object obj)overload, then it wouldn't be called here? – smartcaveman May 05 '13 at 19:46
  • @smartcaveman correct; it will not be called unless you use `dynamic`, or have a `T : SomeBaseType` clause, where the operator is known for `SomeBaseType` – Marc Gravell May 05 '13 at 23:51
  • Or in one line, `return obj == null || !typeof(T).IsValueType || Nullable.GetUnderlyingType(typeof(T)) != null;` :) – nawfal Jul 02 '16 at 07:16
  • If you cast a nullable object to `object`, this method fails spectacularly. To test this, try `DateTime` by itself, then `(object)DateTime`: `DateTime` passes (i.e., it is not nullable); however, casting to `object` appears to...make it nullable? What happens if you just have `object`, but need to make sure it's actual type if nullable? If it is cast to `object`, it always appears to be nullable :-( –  Feb 05 '17 at 20:45
  • @James `object ` is nullable, and if you cast it to object then T===object. The solution there is to use GetType instead of typeof(T) – Marc Gravell Feb 05 '17 at 20:47
  • For .NET Standard, replace `if (!type.IsValueType)` with `if (!type.GetTypeInfo().IsValueType)`. – Omar Muscatello Oct 13 '17 at 06:52
  • (obj == null) may not work if you overloaded the == operator for the class T – cat_in_hat Jul 31 '18 at 00:49
  • @FoundWaldoException it also may not work if you have an implicit conversion operator from, say, string – Marc Gravell Jul 31 '18 at 07:10
  • All tests in IsNullable() function are of variable type T and not of variable (argument obj) value it self. So basically all results are known at compile time (and we know it by type of variable it self - which renders this function pointless). Although this would satisfy 90% code, but when we box values to object (for example object a = (byte)1, b = (short)2, c = (int)3, etc.), this function fails testing (a,b,c, etc...) saying boxed value is nullable type when it's not. Problem is also in .NET that reflected all Nullable types to their UnderlyingSystemType when boxed to object. – SoLaR Aug 21 '19 at 07:57
  • @SoLaR if you're having problems with a boxed translation, I could only comment *if there's code*, but if you're literally using this version with boxed values, then you're asking about `` which is of course nullable – Marc Gravell Aug 21 '19 at 08:16
  • OP is looking for IsNullable(of object type), check his edit. OP wants to test 'obj' variable, and it's boxed boolean in his case. I am looking for something similar and MSDN had no answer, so I am digging SO, if someone tried to extract internal .Net attributes of type if something had left the trace of Nullable type when boxed. edit: Actually his answer is in fieldInfo.FieldType, and check if generic and Nullable. – SoLaR Aug 21 '19 at 08:32
50

There is a very simple solution using method overloads

http://deanchalk.com/is-it-nullable/

excerpt:

public static class ValueTypeHelper
{
    public static bool IsNullable<T>(T t) { return false; }
    public static bool IsNullable<T>(T? t) where T : struct { return true; }
}

then

static void Main(string[] args)
{
    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    bool result1 = ValueTypeHelper.IsNullable(a); // false
    bool result2 = ValueTypeHelper.IsNullable(b); // true
    bool result3 = ValueTypeHelper.IsNullable(c); // false
    bool result4 = ValueTypeHelper.IsNullable(d); // false
    bool result5 = ValueTypeHelper.IsNullable(e); // true
    bool result6 = ValueTypeHelper.IsNullable(f); // true
Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
  • 9
    plus one for you sir for adding test cases. I've used those test cases for checking all the other answers. More people should go this extra bit. – Marty Neal Jan 07 '11 at 21:06
  • 4
    For what it's worth, this doesn't work in VB.NET. It results in a compiler error of "_Overload resolution failed because no accessible 'IsNullable' is most specific for these arguments_" in all situations where `True` would be returned. – ckittel Aug 23 '11 at 18:39
  • 1
    I really like this solution - and it is a shame VB cannot handle it. I tried working around with ValueType but ran into trouble with VB compiler being inconsistent about which overload to use based on whether it was called as a shared method or an extension, I even raised a question about this as it seems weird: http://stackoverflow.com/questions/12319591/how-does-vb-net-compiler-choose-which-extension-overload-to-run – James Close Sep 07 '12 at 14:03
  • 25
    You're checking the **compile-time** type, but it's already obvious (from intellisense) if the compile-time type is nullable (`System.Nullable<>`). If you say `object g = e;` and then `ValueTypeHelper.IsNullable(g)`, what do you expect to obtain? – Jeppe Stig Nielsen Dec 03 '12 at 14:36
  • 20
    I just verified; **this does not work**, as Jeppe said. If the variables are cast to object, it will always return false. So you cannot determine the type of an unknown object at runtime this way. The only time this works is if the type is fixed at compile-time, and in that case you do not need a runtime check at all. – HugoRune Jul 02 '13 at 13:59
  • @Downvoters It is an absolutely valid and wise solution. It uses compile type type resolution and has no overhead at runtime. Obviously, it does not work for run-time type checking, when you have a `Type` object. It is useful with generic type arguments when you are not sure about the passed type. – Mohammad Dehghan May 16 '17 at 06:21
  • 1
    @MohammadDehghan, one should pass an argument for a type parameter. The argument will either be nullable or non-nullable in this case. For the solution presented in the answer to work one should know whether it is nullable or non-nullable before calling the methods. But in case one knows this, then there is no use in calling the methods. Hence, the answer is confusing and wrong. – qqqqqqq Feb 09 '20 at 11:30
  • JeppeStigNielsen and HugoRune are right, casting to `object` erases "nullability" from the type. [More details](https://stackoverflow.com/a/30483921/7585517) – PolarBear Jul 09 '21 at 09:13
43

This works for me and seems simple:

static bool IsNullable<T>(T obj)
{
    return default(T) == null;
}

For value types:

static bool IsNullableValueType<T>(T obj)
{
    return default(T) == null && typeof(T).BaseType != null && "ValueType".Equals(typeof(T).BaseType.Name);
}
Erik
  • 459
  • 4
  • 4
  • 9
    For what it's worth, this is also the test [used by Microsoft](http://referencesource.microsoft.com/#mscorlib/system/collections/objectmodel/readonlycollection.cs,219) – canton7 May 06 '15 at 09:29
  • 2
    Nice... Is this not the top answer cause it came later? I find the top answer so confusing. – Vincent Buscarello Oct 15 '18 at 19:10
  • 2
    This should be the top answer. After days of trying different methods I randomly thought of this solution, tried it, and it seems to be working perfectly (compared to the top-rated answer) – user3163495 Apr 26 '19 at 17:27
  • 4
    This is an excellent solution to find out if any instance can be set to NULL, but it will return true for *everything* that can be set to null, including ordinary objects. It's important to realize that the original question specifically wanted to detect Nullable ValueTypes. – JamesHoux Aug 22 '19 at 01:32
  • The used by Microsoft is now at [this line](https://referencesource.microsoft.com/#mscorlib/system/collections/objectmodel/readonlycollection.cs,205). – vernou Nov 10 '20 at 08:29
  • this should be the selected answer – Desolator Nov 27 '20 at 01:41
  • Will this even work if the object is passed on as Object, though? (like, in a `List` of query parameters to be passed on to a query) It'll just call `IsNullableValueType` and always return `true`. – Nyerguds May 05 '22 at 10:57
30

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<>);
}
Allon Guralnek
  • 15,813
  • 6
  • 60
  • 93
  • @ AllonGuralnek There is simplified version down there in my answer. I wanted to make it as edit and as my reputation is not your level, it would be edit without my name on your answer, even so, it seems that review is alway shooting my into leg, that it is adresing author even if it was not. Strange world, some people do not get definitions:). – ipavlu Nov 10 '15 at 20:01
  • @ipavlu: Your version is not simplified, it's in fact more complicated. I think you mean it's optimized since you cache the result. That makes it more difficult to understand. – Allon Guralnek Nov 10 '15 at 21:36
  • @ AllonGuralnek static generic class and static one time initialized fields, that is complicated? Dear God, I made terrible crime :). – ipavlu Nov 11 '15 at 00:48
  • @ipavku: Yes, because it has nothing to do with the question "How to check if an object is nullable?". I try to keep it simple and to the point, and I avoid introducing unneeded and unrelated concepts. – Allon Guralnek Nov 11 '15 at 05:36
  • I dont understand the practical importance of all that for this question. You write *`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*. For the given question it *is* a general reflective solution. For e.g, `Nullable.GetUnderlyingType` will return `null` for both `int` as well as `List`. It returns for only `Nullable`. – nawfal Jul 02 '16 at 07:29
  • Your is `Nullable` method could be just `return Nullable.GetUnderlyingType(typeof(T)) != null;`. More readable. I can see an argument for your approach if it is about performance. – nawfal Jul 02 '16 at 07:30
  • 1
    @nawfal: If I understood you correctly, your questing my implementation in the face of the existence of `Nullable.GetUnderlyingType()` that already provided by the framework. Why not just use the method in the framework? Well, you should. It is clearer, more concise and better tested. But in my post I'm trying to teach how to use reflection to get the information you want, so that someone can apply it to any type (by replacing `typeof(Nullable<>)` with any other type). If you look at the sources of `GetUnderlyingType()` (original or decompiled), you'll see it is *very* similar to my code. – Allon Guralnek Jul 02 '16 at 19:05
  • @AllonGuralnek Ah I see, thanks for clarification. I just got mislead by your answer that I thought there was a slight hint on `Nullable.GetUnderlyingType` being not good enough in some way.. – nawfal Jul 02 '16 at 19:58
  • Personally, I think this answer should be the accepted one. I just tested both the accepted answer and yours and yours passes the tricky tests. For example, in the accepted answer, casting a non-nullable to `object` always comes back nullable. Using your solution, it passes regardless of what it is cast to. Though the two may be similar, something is definitely different in this regard. +1 for you (reflection ftw)! –  Feb 05 '17 at 20:52
  • True, this one is more close to real answer then most. But this fails for boxed values. Example: object a = (int?)8; returns IsNullable(a) = false, when the answer should be true. And it's not mistake in code, .NET reflected UndedlyingSystemType, instead of Nullable, to boxed value. Yes, we have lost generic type definition information in the process of boxing value. – SoLaR Aug 21 '19 at 08:11
  • Copilot generated almost identical code as this when I was trying to figure this out, so I guess that's plus 1 from me and plus1 from AI. Unfortunately, the latter will have to come here itself because I only get one vote. – rory.ap Jul 09 '23 at 13:25
  • @rory.ap: I did not consider the target audience of AI when I wrote this answer 12 years ago. It's funny, as someone who doesn't pay for it, I don't have access to my own answers through Copilot. I wonder, is it equivalent to an artist being denied access to an exhibition of his own works? – Allon Guralnek Jul 10 '23 at 14:09
20

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?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    This threw me off a bit. e.g. int? i = 5; typeof(i) returns System.Int32 instead of Nullable -- typeof(int?) returns Nullable.. where can I get some clarity on this topic? – Gishu Feb 12 '09 at 11:39
  • 3
    typeof(i) will give a compiler error- you can't use typeof with a variable. What did you actually do? – Jon Skeet Feb 12 '09 at 11:47
  • 15
    i.GetType() will box to Object first, and there's no such thing as a boxed nullable type - Nullable gets boxed to a null reference or a boxed int. – Jon Skeet Feb 12 '09 at 14:52
  • That way is better than Nullable.GetUnderlyingType(type) != null ? – Kiquenet Nov 28 '13 at 13:27
  • @Kiquenet: We don't *have* the type here - just the value. – Jon Skeet Nov 28 '13 at 13:28
  • Marked answer has: Type type = typeof(T); Which better solution about it? – Kiquenet Nov 28 '13 at 13:40
  • @Kiquenet: Well that's changing the signature from the original question - basically the question wasn't clear enough about what the OP was trying to achieve. – Jon Skeet Nov 28 '13 at 13:42
  • This returns false for nullable value types. e.g. `int? f = 3`. f/int? is nullable here. – nawfal Aug 15 '20 at 16:18
  • @nawfal: Unfortunately the question was very unclear - I certainly wouldn't answer it these days. Fundamentally if the OP was trying to get an *object* of type `Nullable` for some T, they can't do so due to the way that boxing happens... – Jon Skeet Aug 15 '20 at 17:32
14

The simplest solution I came up with is to implement Microsoft's solution (How to: Identify a Nullable Type (C# Programming Guide)) as an extension method:

public static bool IsNullable(this Type type)
{
    return Nullable.GetUnderlyingType(type) != null;
}

This can then be called like so:

bool isNullable = typeof(int).IsNullable();

This also seems a logical way to access IsNullable() because it fits in with all of the other IsXxxx() methods of the Type class.

sclarke81
  • 1,739
  • 1
  • 18
  • 23
  • 1
    Didn't you want to use "==" instead of "!=" ? – vkelman Mar 29 '19 at 17:02
  • Good spot @vkelman Instead of making that change I've updated the answer to use the current suggestion from Microsoft as this has changed since I wrote this. – sclarke81 Apr 01 '19 at 08:11
11

There are two issues here: 1) testing to see whether a Type is nullable; and 2) testing to see whether an object represents a nullable Type.

For issue 1 (testing a Type), here's a solution I've used in my own systems: TypeIsNullable-check solution

For issue 2 (testing an object), Dean Chalk's solution above works for value types, but it doesn't work for reference types, since using the <T> overload always returns false. Since reference types are inherently nullable, testing a reference type should always return true. Please see the note [About "nullability"] below for an explanation of these semantics. Thus, here's my modification to Dean's approach:

    public static bool IsObjectNullable<T>(T obj)
    {
        // If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
        if (!typeof(T).IsValueType || obj == null)
            return true;

        // Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
        return false; 
    }

    public static bool IsObjectNullable<T>(T? obj) where T : struct
    {
        // Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
        return true;
    }

And here's my modification to the client-test code for the above solution:

    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    string g = "something";

    bool isnullable = IsObjectNullable(a); // false 
    isnullable = IsObjectNullable(b); // true 
    isnullable = IsObjectNullable(c); // true 
    isnullable = IsObjectNullable(d); // true 
    isnullable = IsObjectNullable(e); // true 
    isnullable = IsObjectNullable(f); // true 
    isnullable = IsObjectNullable(g); // true

The reason I've modified Dean's approach in IsObjectNullable<T>(T t) is that his original approach always returned false for a reference type. Since a method like IsObjectNullable should be able to handle reference-type values and since all reference types are inherently nullable, then if either a reference type or a null is passed, the method should always return true.

The above two methods could be replaced with the following single method and achieve the same output:

    public static bool IsObjectNullable<T>(T obj)
    {
        Type argType = typeof(T);
        if (!argType.IsValueType || obj == null)
            return true;
        return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

However, the problem with this last, single-method approach is that performance suffers when a Nullable<T> parameter is used. It takes much more processor time to execute the last line of this single method than it does to allow the compiler to choose the second method overload shown previously when a Nullable<T>-type parameter is used in the IsObjectNullable call. Therefore, the optimum solution is to use the two-method approach illustrated here.

CAVEAT: This method works reliably only if called using the original object reference or an exact copy, as shown in the examples. However, if a nullable object is boxed to another Type (such as object, etc.) instead of remaining in its original Nullable<> form, this method will not work reliably. If the code calling this method is not using the original, unboxed object reference or an exact copy, it cannot reliably determine the object's nullability using this method.

In most coding scenarios, to determine nullability one must instead rely on testing the original object's Type, not its reference (e.g., code must have access to the object's original Type to determine nullability). In these more common cases, IsTypeNullable (see link) is a reliable method of determining nullability.

P.S. - About "nullability"

I should repeat a statement about nullability I made in a separate post, which applies directly to properly addressing this topic. That is, I believe the focus of the discussion here should not be how to check to see if an object is a generic Nullable type, but rather whether one can assign a value of null to an object of its type. In other words, I think we should be determining whether an object type is nullable, not whether it is Nullable. The difference is in semantics, namely the practical reasons for determining nullability, which is usually all that matters.

In a system using objects with types possibly unknown until run-time (web services, remote calls, databases, feeds, etc.), a common requirement is to determine whether a null can be assigned to the object, or whether the object might contain a null. Performing such operations on non-nullable types will likely produce errors, usually exceptions, which are very expensive both in terms of performance and coding requirements. To take the highly-preferred approach of proactively avoiding such problems, it is necessary to determine whether an object of an arbitrary Type is capable of containing a null; i.e., whether it is generally 'nullable'.

In a very practical and typical sense, nullability in .NET terms does not at all necessarily imply that an object's Type is a form of Nullable. In many cases in fact, objects have reference types, can contain a null value, and thus are all nullable; none of these have a Nullable type. Therefore, for practical purposes in most scenarios, testing should be done for the general concept of nullability, vs. the implementation-dependent concept of Nullable. So we should not be hung up by focusing solely on the .NET Nullable type but rather incorporate our understanding of its requirements and behavior in the process of focusing on the general, practical concept of nullability.

Community
  • 1
  • 1
Mark Jones
  • 2,024
  • 1
  • 19
  • 12
11

The simplest way I can figure out is:

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
CARLOS LOTH
  • 4,675
  • 3
  • 38
  • 44
  • +1. Excellent solution for boxed null-able types. I haven't tested this specifically yet. So if anyone else can verify, it would be appreciated. – TamusJRoyce May 02 '12 at 21:20
  • I have already tested it. I had to created a kind of `Nullable` type, but with different semantics. In my situation I should support `null` as a valid value and also support no value at all. So a created an `Optional` type. As it was necessary to support `null` values, I also had to implement code for handling `Nullable` values as part of my implementation. That is where this code came from. – CARLOS LOTH May 08 '12 at 13:52
  • 9
    I think this solution is wrong. Passing a Nullable value type as an argument to a method expecting a parameter of type object should cause boxing to occur. Nullable is a value type and the result of boxing conversion is a reference type. There are no boxed nullables. I believe this method always returns false? – Mishax Nov 17 '12 at 08:34
  • 1
    Any test about it like another answers ? – Kiquenet Nov 28 '13 at 13:36
  • 5
    It doesn't work because of boxing value. It will always return FALSE. – N Rocking Apr 04 '14 at 16:21
6

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.

thinkbeforecoding
  • 6,668
  • 1
  • 29
  • 31
3

Maybe a little bit off topic, but still some interesting information. I find a lot of people that use Nullable.GetUnderlyingType() != null to identity if a type is nullable. This obviously works, but Microsoft advices the following type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) (see http://msdn.microsoft.com/en-us/library/ms366789.aspx).

I looked at this from a performance side of view. The conclusion of the test (one million attempts) below is that when a type is a nullable, the Microsoft option delivers the best performance.

Nullable.GetUnderlyingType(): 1335ms (3 times slower)

GetGenericTypeDefinition() == typeof(Nullable<>): 500ms

I know that we are talking about a small amount of time, but everybody loves to tweak the milliseconds :-)! So if you're boss wants you to reduce some milliseconds then this is your saviour...

/// <summary>Method for testing the performance of several options to determine if a type is     nullable</summary>
[TestMethod]
public void IdentityNullablePerformanceTest()
{
    int attempts = 1000000;

    Type nullableType = typeof(Nullable<int>);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
    {
        Assert.IsTrue(Nullable.GetUnderlyingType(nullableType) != null, "Expected to be a nullable"); 
    }

    Console.WriteLine("Nullable.GetUnderlyingType(): {0} ms", stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();

    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
   {
       Assert.IsTrue(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>), "Expected to be a nullable");
   }

   Console.WriteLine("GetGenericTypeDefinition() == typeof(Nullable<>): {0} ms", stopwatch.ElapsedMilliseconds);
   stopwatch.Stop();
}
Roel van Megen
  • 341
  • 3
  • 8
  • 1
    Hi, there is probably one issue with measuring time, the Assert can affect results. Have you tested without Assert? Also Console.WriteLine should be outside metered area. +1 for an attempt to quantify performance issues:). – ipavlu Nov 11 '15 at 01:19
  • @ipavlu `Console.WriteLine` is indeed outside metered area ;) – nawfal Jul 02 '16 at 12:31
  • Roel, as ipavlu has mentioned, `Assert` should be outside the loop. Secondly, you should also test it against non-nullables as well to test for false cases. I did a similar test (2 nulables and 4 non-nullables) and I get ~2 seconds for `GetUnderlyingType` and ~1 second for `GetGenericTypeDefinition`, ie, `GetGenericTypeDefinition` is twice faster (not thrice). – nawfal Jul 02 '16 at 12:38
  • Did another round with 2 nullables and 2 non-nullables - this time `GetUnderlyingType` was 2.5 times slower. With only non-nullables - this time both are neck and neck. – nawfal Jul 02 '16 at 13:03
  • But more importantly, `GetUnderlyingType` is useful when you have to check for nullability & get underlying type if it is nullable. This is very useful and you see patterns often like `Activator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type)`. It is like `as` keyword, checks for the cast as well as does it & return result. If you want to get the underlying type of nullable back then doing a `GetGenericTypeDefinition` check and then getting generic type will be a bad idea. Also `GetUnderlyingType` is much more readable & memorable. I wouldnt mind it if I am doing it only ~1000 times. – nawfal Jul 02 '16 at 13:04
3

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<>));
NetMage
  • 26,163
  • 3
  • 34
  • 55
0

This version:

  • caching results is faster,
  • does not require unnecessary variables, like Method(T obj)
  • NOT COMPLICATED :),
  • just static generic class, that has one time computed fields

:

public static class IsNullable<T>
{
    private static readonly Type type = typeof(T);
    private static readonly bool is_nullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    public static bool Result { get { return is_nullable; } }
}

bool is_nullable = IsNullable<int?>.Result;
ipavlu
  • 1,617
  • 14
  • 24
  • I think you answered your-self with that static declaration 'is_nullable'. Tip: declare objects with int? (object a = (int?)8;) and see what happens. – SoLaR Aug 21 '19 at 08:16
0

Here is what I came up with, as everything else seemed to fail - at least on the PLC - Portable Class Library / .NET Core with >= C# 6

Solution: Extend static methods for any Type T and Nullable<T> and use the fact that the static extension method, matching the underlying type is going to be invoked and takes precedence over the generic T extension-method.

For T:

public static partial class ObjectExtension
{
    public static bool IsNullable<T>(this T self)
    {
        return false;
    }
}

and for Nullable<T>

public static partial class NullableExtension
{
    public static bool IsNullable<T>(this Nullable<T> self) where T : struct
    {
        return true;
    }
}

Using Reflection and type.IsGenericType... did not work on my current set of .NET Runtimes. Nor did the MSDN Documentation help.

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {…}

In part because the Reflection API has been changed quite significantly in .NET Core.

Lorenz Lo Sauer
  • 23,698
  • 16
  • 85
  • 87
-1

a simple way to do this:

    public static bool IsNullable(this Type type)
    {
        if (type.IsValueType) return Activator.CreateInstance(type) == null;

        return true;
    }

these are my unit tests and all passed

    IsNullable_String_ShouldReturn_True
    IsNullable_Boolean_ShouldReturn_False
    IsNullable_Enum_ShouldReturn_Fasle
    IsNullable_Nullable_ShouldReturn_True
    IsNullable_Class_ShouldReturn_True
    IsNullable_Decimal_ShouldReturn_False
    IsNullable_Byte_ShouldReturn_False
    IsNullable_KeyValuePair_ShouldReturn_False

actual unit tests

    [TestMethod]
    public void IsNullable_String_ShouldReturn_True()
    {
        var typ = typeof(string);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Boolean_ShouldReturn_False()
    {
        var typ = typeof(bool);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Enum_ShouldReturn_Fasle()
    {
        var typ = typeof(System.GenericUriParserOptions);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Nullable_ShouldReturn_True()
    {
        var typ = typeof(Nullable<bool>);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Class_ShouldReturn_True()
    {
        var typ = typeof(TestPerson);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Decimal_ShouldReturn_False()
    {
        var typ = typeof(decimal);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Byte_ShouldReturn_False()
    {
        var typ = typeof(byte);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_KeyValuePair_ShouldReturn_False()
    {
        var typ = typeof(KeyValuePair<string, string>);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }
VJPPaz
  • 917
  • 7
  • 21