tags:

views:

1004

answers:

3

Once again one of those: "Is there an easier built-in way of doing things instead of my helper method?"

So it's easy to get the underlying type from a nullable type, but how do I get the nullable version of a .NET type?

So I have

typeof(int)
typeof(DateTime)
System.Type t = something;

and I want

int? 
DateTime?

or

Nullable<int> (which is the same)
if t is primitive then Nullable<T> else just T

Any suggestions? (Is there something built in.) Thanks in advance.

+21  A: 

Here is the code I use:

Type GetNullableType(Type type) {
    // Use Nullable.GetUnderlyingType() to remove the Nullable<T> wrapper if type is already nullable.
    type = Nullable.GetUnderlyingType(type);
    if (type.IsValueType)
        return typeof(Nullable<>).MakeGenericType(type);
    else
        return type;
}

Edit: Original code had a bug where it would behave unexpectedly if type was itself a Nullable<T>.

Alex Lyman
Nice! This is a really neat solution.
kronoz
Great answer! Just what I was looking for.
AlexDuggleby
Cool solution. What about making it an extension method on Type itself? Seems suitable in this situation.
jolson
Hmmm...wonder what GetNullableType(typeof(int?)) returns....
Mark Brackett
@Mark: Ouch, never though of that possibility. Will edit to fix that bug.
Alex Lyman
+2  A: 

There isn't anything built in that I know of, as the int?, etc. is just syntactic sugar for Nullable<T> and isn't given special treatment beyond that. It's especially unlikely given you're attempting to obtain this from the type information of a given type. Typically that always necessitates some 'roll your own' code as a given. You would have to use Reflection to create a new Nullable type with type parameter of the input type.

Edit: As the comments suggest actually Nullable<> is treated specially, and in the runtime to boot as explained in this article.

kronoz
Actaully, I'm pretty sure the CLR has some special magic for handling Nullable<>'s somewhat differently. I'll need to check this.
TraumaPony
I would be interested in this, happy to admit I'm wrong if that's the case :-)
kronoz
The CLR does have special handling for Nullables. http://blogs.msdn.com/somasegar/archive/2005/08/11/450640.aspx
Mark Brackett
Since you can add two `int?` via the `+` operator, we *know* that `Nullable`s get special treatment because this kind of generic operator overloading wouldn't work otherwise.
Konrad Rudolph
A: 

Lyman's answer is great and has helped me, however, there's one more bug which needs to be fixed.

Nullable.GetUnderlyingType(type) should only be called iff the type isn't already a Nullable type. Otherwise, it seems to erroneously return null when the type derives from System.RuntimeType (such as when I pass in typeof(System.Int32) ). The below version avoids needing to call Nullable.GetUnderlyingType(type) by checking if the type is Nullable instead.

Below you'll find an ExtensionMethod version of this method which will immediately return the type unless it's a ValueType that's not already Nullable.

Type NullableVersion(this Type sourceType)
{
    if(sourceType == null)
    {
        // Throw System.ArgumentNullException or return null, your preference
    }
    else if(sourceType == typeof(void))
    { // Special Handling - known cases where Exceptions would be thrown
        return null; // There is no Nullable version of void
    }

    return !sourceType.IsValueType
            || (sourceType.IsGenericType
               && sourceType.GetGenericTypeDefinition() == typeof(Nullable<>) )
        ? sourceType
        : typeof(Nullable<>).MakeGenericType(sourceType);
}

(I'm sorry, but I couldn't simply post a comment to Lyman's answer because I'm new and don't yet have enough rep.)

Thracx