How to check if an object is nullable?
Asked Answered
C

14

233

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.

Cabotage answered 17/12, 2008 at 14:17 Comment(4)
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?Electropositive
String is not a ValueType. It is a Reference type.Lidialidice
This is a really good question! The 'Type.IsNullableType()' is kind of deceiving because it actually only checks for the type being a 'Nullable<T>', 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)Selfinduced
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<T> variable T (in your case of Boolean type, instead of Nullable<Boolean>), it's a boxing problem.Kindle
B
311

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

Bolivar answered 17/12, 2008 at 14:20 Comment(25)
The last line is only valid if you somehow manage to get a boxed Nullable<T> instead of boxing straight to T. It's possible, but tricky to achieve from what I remember.Reconnoiter
This code was helpful for me, not because I got a boxed Nullable<T> 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).Pickel
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.Foxed
@Foxed 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.Bolivar
@Foxed 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)Bolivar
I had "nullable" and "is Nullable<T>" 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<T> (i.e. var x = (Nullable<T>) obj wouldn't throw) . Which is not the same.Foxed
Will (obj == null) throw an exception when obj = 1 ?Parisian
@QiFan no, why would it? It will just be false.Bolivar
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.Qadi
@Justin Nullable GetUnderlyingType with typeof(T) should workBolivar
@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."Notable
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<object>(new Nullable<int>(5)) return? What does IsNullable<int?>(5) return?Notable
i think your "obvious" clause should say ReferenceEquals(obj,null) , just to be safeCharlotte
@Charlotte no need; generics doesn't have support for operators, so that will always be an unbox_any plus reference checkBolivar
@MarcGravell - so even if the particular T has an ==(T whatever, object obj)overload, then it wouldn't be called here?Charlotte
@Charlotte correct; it will not be called unless you use dynamic, or have a T : SomeBaseType clause, where the operator is known for SomeBaseTypeBolivar
Or in one line, return obj == null || !typeof(T).IsValueType || Nullable.GetUnderlyingType(typeof(T)) != null; :)Kehoe
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 :-(Discretional
@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)Bolivar
For .NET Standard, replace if (!type.IsValueType) with if (!type.GetTypeInfo().IsValueType).Doris
(obj == null) may not work if you overloaded the == operator for the class TGaytan
@FoundWaldoException it also may not work if you have an implicit conversion operator from, say, stringBolivar
All tests in IsNullable<T>() 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<T> types to their UnderlyingSystemType when boxed to object.Kindle
@Kindle 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 <object> which is of course nullableBolivar
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<T> type when boxed. edit: Actually his answer is in fieldInfo.FieldType, and check if generic and Nullable<T>.Kindle
P
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
Postal answered 9/11, 2010 at 8:50 Comment(8)
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.Overissue
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.Betty
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: #12320091Microhenry
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?Notable
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.Kapoor
@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.Carpophagous
@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.Patronizing
JeppeStigNielsen and HugoRune are right, casting to object erases "nullability" from the type. More detailsDaniels
P
45

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);
}
Prehension answered 30/4, 2014 at 20:52 Comment(7)
For what it's worth, this is also the test used by MicrosoftParkman
Nice... Is this not the top answer cause it came later? I find the top answer so confusing.Reinwald
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)Sachsse
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.Affluence
The used by Microsoft is now at this line.Slither
this should be the selected answerWarmedover
Will this even work if the object is passed on as Object, though? (like, in a List<Object> of query parameters to be passed on to a query) It'll just call IsNullableValueType<Object> and always return true.Gilly
F
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<>);
}
Forensics answered 3/1, 2011 at 11:58 Comment(12)
@ 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:).Upali
@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.Forensics
@ AllonGuralnek static generic class and static one time initialized fields, that is complicated? Dear God, I made terrible crime :).Upali
@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.Forensics
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<int>. It returns for only Nullable<int>.Kehoe
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.Kehoe
@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.Forensics
@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..Kehoe
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)!Discretional
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<T>, to boxed value. Yes, we have lost generic type definition information in the process of boxing value.Kindle
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.Hyaluronidase
@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?Forensics
R
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?

Reconnoiter answered 17/12, 2008 at 14:21 Comment(9)
This threw me off a bit. e.g. int? i = 5; typeof(i) returns System.Int32 instead of Nullable<Int32> -- typeof(int?) returns Nullable<Int32>.. where can I get some clarity on this topic?Fidelfidela
typeof(i) will give a compiler error- you can't use typeof with a variable. What did you actually do?Reconnoiter
i.GetType() will box to Object first, and there's no such thing as a boxed nullable type - Nullable<int> gets boxed to a null reference or a boxed int.Reconnoiter
That way is better than Nullable.GetUnderlyingType(type) != null ?Confiding
@Kiquenet: We don't have the type here - just the value.Reconnoiter
Marked answer has: Type type = typeof(T); Which better solution about it?Confiding
@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.Reconnoiter
This returns false for nullable value types. e.g. int? f = 3. f/int? is nullable here.Kehoe
@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<T> for some T, they can't do so due to the way that boxing happens...Reconnoiter
T
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.

Thriftless answered 22/12, 2016 at 11:0 Comment(2)
Didn't you want to use "==" instead of "!=" ?Ohmage
Good spot @Ohmage 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.Thriftless
T
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.

Thornberry answered 14/10, 2011 at 0:27 Comment(0)
C
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<>);
}
Cornet answered 15/3, 2012 at 2:10 Comment(5)
+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.Electropositive
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.Cornet
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?Tush
Any test about it like another answers ?Confiding
It doesn't work because of boxing value. It will always return FALSE.Whimwham
A
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.

Alphabetic answered 17/12, 2008 at 16:10 Comment(0)
M
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();
}
Marmara answered 4/7, 2014 at 15:32 Comment(5)
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:).Upali
@Upali Console.WriteLine is indeed outside metered area ;)Kehoe
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).Kehoe
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.Kehoe
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.Kehoe
S
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<>));
Sparling answered 21/1, 2019 at 20:43 Comment(0)
U
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;
Upali answered 10/11, 2015 at 20:5 Comment(1)
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.Kindle
D
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.

Drabbet answered 25/8, 2016 at 6:27 Comment(0)
P
-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);
    }
Provide answered 18/8, 2015 at 3:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.