Convert string to nullable type (int, double, etc...)

144,481

Solution 1

Another thing to keep in mind is that the string itself might be null.

public static Nullable<T> ToNullable<T>(this string s) where T: struct
{
    Nullable<T> result = new Nullable<T>();
    try
    {
        if (!string.IsNullOrEmpty(s) && s.Trim().Length > 0)
        {
            TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
            result = (T)conv.ConvertFrom(s);
        }
    }
    catch { } 
    return result;
}

Solution 2

You could try using the below extension method:

public static T? GetValueOrNull<T>(this string valueAsString)
    where T : struct 
{
    if (string.IsNullOrEmpty(valueAsString))
        return null;
    return (T) Convert.ChangeType(valueAsString, typeof(T));
}

This way you can do this:

double? amount = strAmount.GetValueOrNull<double>();
int? amount = strAmount.GetValueOrNull<int>();
decimal? amount = strAmount.GetValueOrNull<decimal>();

Solution 3

What about this:


double? amount = string.IsNullOrEmpty(strAmount) ? (double?)null : Convert.ToDouble(strAmount);

Of course, this doesn't take into account the convert failing.

Solution 4

I wrote this generic type converter. It works with Nullable and standard values, converting between all convertible types - not just string. It handles all sorts of scenarios that you'd expect (default values, null values, other values, etc...)

I've been using this for about a year in dozens of production programs, so it should be pretty solid.

    public static T To<T>(this IConvertible obj)
    {
        Type t = typeof(T);

        if (t.IsGenericType
            && (t.GetGenericTypeDefinition() == typeof(Nullable<>)))
        {
            if (obj == null)
            {
                return (T)(object)null;
            }
            else
            {
                return (T)Convert.ChangeType(obj, Nullable.GetUnderlyingType(t));
            }
        }
        else
        {
            return (T)Convert.ChangeType(obj, t);
        }
    }

    public static T ToOrDefault<T>
                 (this IConvertible obj)
    {
        try
        {
            return To<T>(obj);
        }
        catch
        {
            return default(T);
        }
    }

    public static bool ToOrDefault<T>
                        (this IConvertible obj,
                         out T newObj)
    {
        try
        {
            newObj = To<T>(obj);
            return true;
        }
        catch
        {
            newObj = default(T);
            return false;
        }
    }

    public static T ToOrOther<T>
                           (this IConvertible obj,
                           T other)
    {
        try
        {
            return To<T>(obj);
        }
        catch
        {
            return other;
        }
    }

    public static bool ToOrOther<T>
                             (this IConvertible obj,
                             out T newObj,
                             T other)
    {
        try
        {
            newObj = To<T>(obj);
            return true;
        }
        catch
        {
            newObj = other;
            return false;
        }
    }

    public static T ToOrNull<T>
                          (this IConvertible obj)
                          where T : class
    {
        try
        {
            return To<T>(obj);
        }
        catch
        {
            return null;
        }
    }

    public static bool ToOrNull<T>
                      (this IConvertible obj,
                      out T newObj)
                      where T : class
    {
        try
        {
            newObj = To<T>(obj);
            return true;
        }
        catch
        {
            newObj = null;
            return false;
        }
    }

Solution 5

You might want to try:

TypeConverter conv = TypeDescriptor.GetConverter(typeof(int));
conv.ConvertFrom(mystring);

do your own null check and return int? if necessary. You'll also want to wrap that in a try {}

Share:
144,481
Nathan Koop
Author by

Nathan Koop

I'm currently a Sr. Dev/tech lead at Bold Commerce. I work with PHP, Laravel, Eloquent, React, Redux, GoLang, MySQL and more.

Updated on July 08, 2022

Comments

  • Nathan Koop
    Nathan Koop almost 2 years

    I am attempting to do some data conversion. Unfortunately, much of the data is in strings, where it should be int's or double, etc...

    So what I've got is something like:

    double? amount = Convert.ToDouble(strAmount);
    

    The problem with this approach is if strAmount is empty, if it's empty I want it to amount to be null, so when I add it into the database the column will be null. So I ended up writing this:

    double? amount = null;
    if(strAmount.Trim().Length>0)
    {
        amount = Convert.ToDouble(strAmount);
    }
    

    Now this works fine, but I now have five lines of code instead of one. This makes things a little more difficult to read, especially when I have a large amount of columns to convert.

    I thought I'd use an extension to the string class and generic's to pass in the type, this is because it could be a double, or an int, or a long. So I tried this:

    public static class GenericExtension
    {
        public static Nullable<T> ConvertToNullable<T>(this string s, T type) where T: struct
        {
            if (s.Trim().Length > 0)
            {
                return (Nullable<T>)s;
            }
            return null;
        }
    }
    

    But I get the error: Cannot convert type 'string' to 'T?'

    Is there a way around this? I am not very familiar with creating methods using generics.

  • bdukes
    bdukes about 15 years
    If you cast either of the return values to a double? (or int?, etc), then it will be able to convert them to the final double?. See the change above.
  • Michael Meadows
    Michael Meadows about 15 years
    You can omit the "T type" parameter since it's not used.
  • LukeH
    LukeH about 15 years
    +1, Just beat me to it. A small nitpick: the converted value needs to be assigned directly to result, not to result.Value. ie, "result = (T)conv.ConvertFrom(s);".
  • John Kraft
    John Kraft about 15 years
    Sorry about that. Always forget the cast until the compiler screams. :)
  • RichardOD
    RichardOD almost 15 years
    Luke- that's a little more than a nitpick- the code doesn't compile unless you do this!
  • TheSoftwareJedi
    TheSoftwareJedi almost 15 years
    See my answer below which handles nullable and standard types in the same methods. Also provides a boatload more options... :)
  • Zaffiro
    Zaffiro almost 15 years
    IMHO this is the most elegant solution to the problem
  • Sergej Andrejev
    Sergej Andrejev over 13 years
    This can be simplified a bit with string.IsNullOrWhiteSpace() if you use .Net4
  • AaronHS
    AaronHS over 12 years
    actually.. this solution doesn't work. changetype doesn't convert to nullable types. instead use typeconverter
  • Pavel Hodek
    Pavel Hodek over 11 years
    Who was downvoting please add a comment what's wrong with this universal solution.
  • Paul Groke
    Paul Groke over 11 years
    I don't think ignoring all conversion errors is the right thing to do. Also you should probably not swallow all kinds of exceptions. At least re-throw OutOfMemoryException if you cannot narrow it down to a fixed set of exception types.
  • Paul Groke
    Paul Groke over 11 years
    Well, first there's something very wrong with your answer, and that's the "you can forget all other answers". Which would be wrong even if it were true (which it is not). And what's wrong with the "universal solution" is that it's full of bad performance (typeName.IndexOf? really?) and strang behaviour (the shown TryConvert function doesn't even handle null values correctly).
  • Steve
    Steve over 9 years
    this will fail if you aren't null and you try amount.HasValue and declare amount as var.
  • minerva
    minerva over 8 years
    @andrefadila - To use: string sampleVendorId = ""; int? vendorId = sampleVendorId.ToNullable<int>();
  • rayzinnz
    rayzinnz about 8 years
    Hi thanks this solved it for me. FYI I was using VB.NET, and the VB equivilant CType(Object, Nullable(Of Double)) works fine with strings
  • David
    David over 7 years
    The call conv.ConvertFrom doesn't convert a nullable type of T, which makes this function a little counter intuitive. You don't need a try catch in this function. These three lines of code makes it all: if (string.IsNullOrWhiteSpace(stringObject)) return null; var conv = TypeDescriptor.GetConverter(typeof(T)); return (T?)conv.ConvertFrom(stringObject);
  • Arci
    Arci over 6 years
    Use result = (T)Convert.ChangeType(s, typeof(T), System.Globalization.CultureInfo.InvariantCulture); for conversion from object. TypeConverter.convertFrom does not support conversion between decimal and int.
  • S.Serpooshan
    S.Serpooshan almost 6 years
    @DaveWut No, if we the string is entered by user, it may be an invalid number like as "abc1357" instead of "1357". So we need to check if conversion fails...
  • S.Serpooshan
    S.Serpooshan almost 6 years
    @JoelCoehoorn Good code! but I think we could do it also without using those try/catch block and GetConverter codes... as in my answer
  • Marcus.D
    Marcus.D almost 5 years
    That's what I need to know... I have to use the underlying type of a Nullable-Type when using the Convert.ChangeType-Method. Because it don't works with a Nullable-Typ for parameter conversionType.
  • S.Serpooshan
    S.Serpooshan about 4 years
    @MassimilianoKraus may be, but it is a simple 12 lines code, written once, but using all the times. And, as I said, it should/may be faster than using those TypeDescriptor.GetConverter... codes. This is just another way.
  • wazz
    wazz about 4 years
    is there a version of your first example that can be used with strings?