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

C#.NetGenericsExtension MethodsType Conversion

C# Problem Overview


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.

C# Solutions


Solution 1 - C#

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 - C#

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 - C#

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 - C#

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 - C#

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 {}

Solution 6 - C#

Give this a shot...

public delegate bool TryParseDelegate<T>(string data, out T output);

public static T? ToNullablePrimitive<T>(this string data, 
    TryParseDelegate<T> func) where T:struct
{
    string.IsNullOrEmpty(data) return null;

    T output;

    if (func(data, out output))
    {
        return (T?)output;
    }

    return null;
}

Then call it like this...

void doStuff()
{
    string foo = "1.0";
    
    double? myDouble = foo.ToNullablePrimitive<double>(double.TryParse);
    
    foo = "1";
    
    int? myInt = foo.ToNullablePrimitive<int>(int.TryParse);
    
    foo = "haha";
    
    int? myInt2 = foo.ToNullablePrimitive<int>(int.TryParse);
}

Solution 7 - C#

I like Joel's answer, but I've modified it slightly as I'm not a fan of eating exceptions.

    /// <summary>
    /// Converts a string to the specified nullable type.
    /// </summary>
    /// <typeparam name="T">The type to convert to</typeparam>
    /// <param name="s">The string to convert</param>
    /// <returns>The nullable output</returns>
    public static T? ToNullable<T>(this string s) where T : struct
    {
        if (string.IsNullOrWhiteSpace(s))
            return null;
        
        TypeConverter conv = TypeDescriptor.GetConverter(typeof (T));
        return (T) conv.ConvertFrom(s);
    }

    /// <summary>
    /// Attempts to convert a string to the specified nullable primative.
    /// </summary>
    /// <typeparam name="T">The primitive type to convert to</typeparam>
    /// <param name="data">The string to convert</param>
    /// <param name="output">The nullable output</param>
    /// <returns>
    /// True if conversion is successfull, false otherwise.  Null and whitespace will
    /// be converted to null and return true.
    /// </returns>
    public static bool TryParseNullable<T>(this string data, out T? output) where T : struct
    {
        try
        {
            output = data.ToNullable<T>();
            return true;
        }
        catch
        {
            output = null;
            return false;
        }
    }

Solution 8 - C#

You can use the following with objects, unfortunately this does not work with strings though.

double? amount = (double?)someObject;

I use it for wrapping a session variable in a property (on a base page).. so my actual usage is (in my base page):

public int? OrganisationID
{
    get { return (int?)Session[Constants.Session_Key_OrganisationID]; }
    set { Session[Constants.Session_Key_OrganisationID] = value; }
}

I'm able to check for null in page logic:

if (base.OrganisationID == null)
    // do stuff

Solution 9 - C#

There is no way around this. Nullable, as well as your method, is constrained to using only value types as it's argument. String is a reference type and hence is incompatible with this declaration.

Solution 10 - C#

public static class GenericExtension
{
    public static T? ConvertToNullable<T>(this String s) where T : struct 
    {
        try
        {
            return (T?)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(s);
        }
        catch (Exception)
        {
            return null;
        }
    }
}

Solution 11 - C#

There is a generic solution (for any type). Usability is good, but implementation should be improved: http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

This allows you to write very clean code like this:

string value = null;
int? x = value.ConvertOrDefault<int?>();

and also:

object obj = 1;  
 
string value = null;
int x = 5;
if (value.TryConvert(out x))
    Console.WriteLine("TryConvert example: " + x); 
 
bool boolean = "false".ConvertOrDefault<bool>();
bool? nullableBoolean = "".ConvertOrDefault<bool?>();
int integer = obj.ConvertOrDefault<int>();
int negativeInteger = "-12123".ConvertOrDefault<int>();
int? nullableInteger = value.ConvertOrDefault<int?>();
MyEnum enumValue = "SecondValue".ConvertOrDefault<MyEnum>();
 
MyObjectBase myObject = new MyObjectClassA();
MyObjectClassA myObjectClassA = myObject.ConvertOrDefault<MyObjectClassA>();

Solution 12 - C#

Here's something based on accepted answer. I removed the try/catch to make sure all the exceptions are not swallowed and not dealt with. Also made sure that the return variable (in accepted answer) is never initialized twice for nothing.

public static Nullable<T> ToNullable<T>(this string s) where T: struct
{
    if (!string.IsNullOrWhiteSpace(s))
    {
        TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
		
        return (T)conv.ConvertFrom(s);
    }
	
    return default(Nullable<T>);
}

Solution 13 - C#

My example for anonimous types:

private object ConvertNullable(object value, Type nullableType)
{
    Type resultType = typeof(Nullable<>).MakeGenericType(nullableType.GetGenericArguments());
    return Activator.CreateInstance(resultType, Convert.ChangeType(value, nullableType.GetGenericArguments()[0]));
}

...

Type anonimousType = typeof(Nullable<int>);
object nullableInt1 = ConvertNullable("5", anonimousType);
// or evident Type
Nullable<int> nullableInt2 = (Nullable<int>)ConvertNullable("5", typeof(Nullable<int>));

Solution 14 - C#

Another variation. This one

  • Does not swallow exceptions
  • Throws a NotSupportedException if the type can not be converted from string. For instance, a custom struct without a type converter.
  • Otherwise returns a (T?)null if the string fails to parse. No need to check for null or whitespace.

using System.ComponentModel;

public static Nullable<T> ToNullable<T>(this string s) where T : struct
{
    var ret = new Nullable<T>();
    var conv = TypeDescriptor.GetConverter(typeof(T));
    
    if (!conv.CanConvertFrom(typeof(string)))
    {
        throw new NotSupportedException();
    }
    
    if (conv.IsValid(s))
    {
        ret = (T)conv.ConvertFrom(s);
    }
    
    return ret;
}

Solution 15 - C#

Let's add one more similar solution to the stack. This one also parses enums, and it looks nice. Very safe.

/// <summary>
    /// <para>More convenient than using T.TryParse(string, out T). 
    /// Works with primitive types, structs, and enums.
    /// Tries to parse the string to an instance of the type specified.
    /// If the input cannot be parsed, null will be returned.
    /// </para>
    /// <para>
    /// If the value of the caller is null, null will be returned.
    /// So if you have "string s = null;" and then you try "s.ToNullable...",
    /// null will be returned. No null exception will be thrown. 
    /// </para>
    /// <author>Contributed by Taylor Love (Pangamma)</author>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="p_self"></param>
    /// <returns></returns>
    public static T? ToNullable<T>(this string p_self) where T : struct
    {
        if (!string.IsNullOrEmpty(p_self))
        {
            var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
            if (converter.IsValid(p_self)) return (T)converter.ConvertFromString(p_self);
            if (typeof(T).IsEnum) { T t; if (Enum.TryParse<T>(p_self, out t)) return t;}
        }

        return null;
    }

https://github.com/Pangamma/PangammaUtilities-CSharp/blob/master/PangammaUtilities/Extensions/ToNullableStringExtension.cs

Solution 16 - C#

The generic answer provided by "Joel Coehoorn" is good.

But, this is another way without using those GetConverter... or try/catch blocks... (i'm not sure but this may have better performance in some cases):

public static class StrToNumberExtensions
{
    public static short ToShort(this string s, short defaultValue = 0) => short.TryParse(s, out var v) ? v : defaultValue;
    public static int ToInt(this string s, int defaultValue = 0) => int.TryParse(s, out var v) ? v : defaultValue;
    public static long ToLong(this string s, long defaultValue = 0) => long.TryParse(s, out var v) ? v : defaultValue;
    public static decimal ToDecimal(this string s, decimal defaultValue = 0) => decimal.TryParse(s, out var v) ? v : defaultValue;
    public static float ToFloat(this string s, float defaultValue = 0) => float.TryParse(s, out var v) ? v : defaultValue;
    public static double ToDouble(this string s, double defaultValue = 0) => double.TryParse(s, out var v) ? v : defaultValue;

    public static short? ToshortNullable(this string s, short? defaultValue = null) => short.TryParse(s, out var v) ? v : defaultValue;
    public static int? ToIntNullable(this string s, int? defaultValue = null) => int.TryParse(s, out var v) ? v : defaultValue;
    public static long? ToLongNullable(this string s, long? defaultValue = null) => long.TryParse(s, out var v) ? v : defaultValue;
    public static decimal? ToDecimalNullable(this string s, decimal? defaultValue = null) => decimal.TryParse(s, out var v) ? v : defaultValue;
    public static float? ToFloatNullable(this string s, float? defaultValue = null) => float.TryParse(s, out var v) ? v : defaultValue;
    public static double? ToDoubleNullable(this string s, double? defaultValue = null) => double.TryParse(s, out var v) ? v : defaultValue;
}

Usage is as following:

var x1 = "123".ToInt(); //123
var x2 = "abc".ToInt(); //0
var x3 = "abc".ToIntNullable(); // (int?)null 
int x4 = ((string)null).ToInt(-1); // -1
int x5 = "abc".ToInt(-1); // -1
        
var y = "19.50".ToDecimal(); //19.50
        
var z1 = "invalid number string".ToDoubleNullable(); // (double?)null
var z2 = "invalid number string".ToDoubleNullable(0); // (double?)0

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNathan KoopView Question on Stackoverflow
Solution 1 - C#Joel CoehoornView Answer on Stackoverflow
Solution 2 - C#Michael MeadowsView Answer on Stackoverflow
Solution 3 - C#John KraftView Answer on Stackoverflow
Solution 4 - C#TheSoftwareJediView Answer on Stackoverflow
Solution 5 - C#Andrew BullockView Answer on Stackoverflow
Solution 6 - C#Adam RobinsonView Answer on Stackoverflow
Solution 7 - C#Colin PlaceView Answer on Stackoverflow
Solution 8 - C#Scotty.NETView Answer on Stackoverflow
Solution 9 - C#JaredParView Answer on Stackoverflow
Solution 10 - C#Daniel BrücknerView Answer on Stackoverflow
Solution 11 - C#Pavel HodekView Answer on Stackoverflow
Solution 12 - C#PhilDulacView Answer on Stackoverflow
Solution 13 - C#ADM-ITView Answer on Stackoverflow
Solution 14 - C#BurnsBAView Answer on Stackoverflow
Solution 15 - C#PangammaView Answer on Stackoverflow
Solution 16 - C#S.SerpooshanView Answer on Stackoverflow