How to parse a string into a nullable int
Asked Answered
F

23

358

I'm wanting to parse a string into a nullable int in C#. ie. I want to get back either the int value of the string or null if it can't be parsed.

I was kind of hoping that this would work

int? val = stringVal as int?;

But that won't work, so the way I'm doing it now is I've written this extension method

public static int? ParseNullableInt(this string value)
{
    if (value == null || value.Trim() == string.Empty)
    {
        return null;
    }
    else
    {
        try
        {
            return int.Parse(value);
        }
        catch
        {
            return null;
        }
    }
}   

Is there a better way of doing this?

EDIT: Thanks for the TryParse suggestions, I did know about that, but it worked out about the same. I'm more interested in knowing if there is a built-in framework method that will parse directly into a nullable int?

Fun answered 5/9, 2008 at 0:22 Comment(2)
You can use string.IsNullOrEmpty(value) to get the if line more clearer.Gremial
Consider to use generics conversion #773578Emersed
C
407

int.TryParse is probably a tad easier:

public static int? ToNullableInt(this string s)
{
    int i;
    if (int.TryParse(s, out i)) return i;
    return null;
}

Edit @Glenn int.TryParse is "built into the framework". It and int.Parse are the way to parse strings to ints.

Craggie answered 5/9, 2008 at 0:25 Comment(14)
one less line: return Int32.TryParse(s, out i) ? i : null;Karyoplasm
I definitely prefer this way to TryParsePractical
I was about to post an example pointing out that a NullReferenceException would occur if the string was null. Instead I learned something interesting about extension methods. string parseOne = "1"; int? resultOne = parseOne.ToNullableInt32(); System.Diagnostics.Debug.Assert(resultOne == 1); string parseEmpty = string.Empty; int? resultEmpty = parseEmpty.ToNullableInt32(); System.Diagnostics.Debug.Assert(!resultEmpty.HasValue); string parseNull = null; int? resultNull = parseNull.ToNullableInt32(); System.Diagnostics.Debug.Assert(!resultNull.HasValue);Bearish
"a" will return null, but it is not int and should throw exceptionMatildematin
@Arsen ... which is exactly what the original question asked for. Look at his code snippet.Craggie
@Chris, the compiler doesn't like your inline if statement (These types are not compatible: 'int' : 'null'). I had to amend it to: return Int32.TryParse(s, out i)? (int?)i : null;Antelope
Int32 is just an alias to int. I would use int.TryParse to keep the types being used in alignment. If/when int is used to represent a different bit length integer (which has happened), Int32 will not line up with int.Adularia
return int.TryParse(s, out i) ? (int?)i : null;Accursed
public static int? _ni(this string s){int i;return int.TryParse(s,out i)?(int?)i:null;}Etamine
@Antelope i : new int?()Popover
@Popover that works too. As does i : default(int?). Thinking about it though, in the return it going to cast the result to an int? anyway, so maybe if it's better if I just do it? Not sure.Antelope
Another line less in C# 7 (inline declaration of i): int.TryParse(s, out int i) ? (int?)i : null;Anaemic
public static int? ToNullableInt(this string s) => (int.TryParse(s, out int i)) ? i : (int?)null;Calcine
Using inline declaration and default with type inference int.TryParse(s, out var i) ? i as int? : defaultBrader
F
225

You can do this in one line, using the conditional operator and the fact that you can cast null to a nullable type (two lines, if you don't have a pre-existing int you can reuse for the output of TryParse):

Pre C#7:

int tempVal;
int? val = Int32.TryParse(stringVal, out tempVal) ? tempVal : (int?)null;

With C#7's updated syntax that allows you to declare an output variable in the method call, this gets even simpler.

int? val = Int32.TryParse(stringVal, out var tempVal) ? tempVal : null;
Fisher answered 5/9, 2008 at 1:14 Comment(8)
You could - but relying on side-effects and order-of-evaluation like that is nasty, when you can make the sequential dependancy obvious by using Matt's syntax. Incidentally, it's handy to use default(int?) for this and similar expressions precisely to avoid the type-inference errors that stem from null's untyped nature without needing to insert casts that may actually execute code.Hallucinosis
That depends on your view of the conditional operator, I think. My mental model is that it is pretty much syntactic sugar for the if-else equivalent, in which case my version and Matt's are close to identical, with his being more explicit, mine more cmopact.Fisher
There is no order-of-evaluation side-effect here. All steps are explicitly ordered and correct.Celio
return int.TryParse(val, out i) ? i : default(int?);Darvon
@Bart's "answer" is the best here!Tabloid
And now in the C# 6, it can be one line! Int32.TryParse(stringVal, out var tempVal) ? tempVal : (int?)null;Butterfield
Just a note here - c# 6 didn't ship with this feature, so don't try declare the var inline (#31724663)Ground
C#7 has, and I clarified the answer to show both pre & post 7 syntax.Forgetful
N
39

[Updated to use modern C# as per @sblom's suggestion]

I had this problem and I ended up with this (after all, an if and 2 returns is soo long-winded!):

int? ToNullableInt (string val)
    => int.TryParse (val, out var i) ? (int?) i : null;

On a more serious note, try not to mix int, which is a C# keyword, with Int32, which is a .NET Framework BCL type - although it works, it just makes code look messy.

Nutcracker answered 28/10, 2008 at 1:26 Comment(5)
Not quite sure this will actually translate into anything that performs better once compiledBushcraft
Even more concise in C# 7: delete the int i; line and just go with return int.TryParse (val, out var i) ? (int?) i : null;Burchett
So for completeness ;-) int? ParseNInt (string val) => int.TryParse (val, out var i) ? (int?) i : null;Nutcracker
With C# 6 this can be reduced to 1 line: return int.TryParse(value, out var result) ? result : (int?)null;Babbittry
I guess you can even reduce with with ommit the unnecessary cast...Leslee
P
32

C# >= 7.1

var result = int.TryParse(foo, out var f) ? f : default;

See C# language versioning to ascertain what language version your project supports

Pupillary answered 24/10, 2018 at 13:12 Comment(2)
how could this work? Tryparse won't work or nullable variables and f in your example would have to be nullable.Errick
tryparse expects to be put in a non-nullable variable, so wouldn't your default(int?) force var to be nullable?Errick
O
18

Glenn Slaven: I'm more interested in knowing if there is a built-in framework method that will parse directly into a nullable int?

There is this approach that will parse directly to a nullable int (and not just int) if the value is valid like null or empty string, but does throw an exception for invalid values so you will need to catch the exception and return the default value for those situations:

public static T Parse<T>(object value)
{
    try { return (T)System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.ToString()); }
    catch { return default(T); }
}

This approach can still be used for non-nullable parses as well as nullable:

enum Fruit { Orange, Apple }
var res1 = Parse<Fruit>("Apple");
var res2 = Parse<Fruit?>("Banana");
var res3 = Parse<int?>("100") ?? 5; //use this for non-zero default
var res4 = Parse<Unit>("45%");

NB: There is an IsValid method on the converter you can use instead of capturing the exception (thrown exceptions does result in unnecessary overhead if expected). Unfortunately it only works since .NET 4 but there's still an issue where it doesn't check your locale when validating correct DateTime formats, see bug 93559.

Overflight answered 25/6, 2011 at 0:17 Comment(1)
I tested this for integers and it is a lot slower than int.TryParse((string)value, out var result) ? result : default(int?);Apriorism
X
10

Try this:

public static int? ParseNullableInt(this string value)
{
    int intValue;
    if (int.TryParse(value, out intValue))
        return intValue;
    return null;
}
Xylol answered 5/9, 2008 at 0:27 Comment(0)
J
10

Old topic, but how about:

public static int? ParseToNullableInt(this string value)
{
     return String.IsNullOrEmpty(value) ? null : (int.Parse(value) as int?);
}

I like this better as the requriement where to parse null, the TryParse version would not throw an error on e.g. ToNullableInt32(XXX). That may introduce unwanted silent errors.

Jamesy answered 22/3, 2011 at 14:17 Comment(2)
That's exactly the point - if the string can't can't be parsed to int, it should return null, not throw an exception.Katalin
if value is non-numeric, int.Parse throws an exception, which is not the same as returning null.Perhaps
M
5

I feel my solution is a very clean and nice solution:

public static T? NullableParse<T>(string s) where T : struct
{
    try
    {
        return (T)typeof(T).GetMethod("Parse", new[] {typeof(string)}).Invoke(null, new[] { s });
    }
    catch (Exception)
    {
        return null;
    }
}

This is of course a generic solution which only require that the generics argument has a static method "Parse(string)". This works for numbers, boolean, DateTime, etc.

Mauramauralia answered 21/6, 2011 at 11:43 Comment(0)
I
5

You can forget all other answers - there is a great generic solution: 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();

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? nullableBoolean = "".ConvertOrDefault();
int integer = obj.ConvertOrDefault();
int negativeInteger = "-12123".ConvertOrDefault();
int? nullableInteger = value.ConvertOrDefault();
MyEnum enumValue = "SecondValue".ConvertOrDefault();

MyObjectBase myObject = new MyObjectClassA();
MyObjectClassA myObjectClassA = myObject.ConvertOrDefault();
Increase answered 10/11, 2011 at 9:4 Comment(2)
This is indeed very useful. In my opinion this should be in the standard c# libraries because conversions are very common in every program ;)Cacia
This is very nice and useful, BUT I may add that it's extremely slow when need to make conversions for each element in a large collection of items. I have tested with 20000 items: by using this approach, converting 8 properties of each item takes up to 1 hour to finish the whole collection. With same sample data but using Matt Hamilton's approach it just takes a few seconds to finish.Everyway
G
4

I would suggest following extension methods for string parsing into int value with ability to define default value in case parsing is not possible:

public static int ParseInt(this string value, int defaultIntValue = 0)
        {
            return int.TryParse(value, out var parsedInt) ? parsedInt : defaultIntValue;
        }

public static int? ParseNullableInt(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return null;

            return value.ParseInt();
        }
Goyette answered 12/3, 2018 at 9:0 Comment(4)
There already so many and even high upvoted answers. Do you really think your answer is needed and adds new quality to this post?Simulate
@L.Guthardt Yes, I think so. As I think my answer bring more universal way to resolve the issue describes in question. Thank you.Goyette
It sure is needed, this is what I was looking for! Thanks :)Orelie
if string is not null or empty but does not contain an int, it throws an exceptionMajewski
B
3

The following should work for any struct type. It is based off code by Matt Manela from MSDN forums. As Murph points out the exception handling could be expensive compared to using the Types dedicated TryParse method.

        public static bool TryParseStruct<T>(this string value, out Nullable<T> result)
            where T: struct 
        {
            if (string.IsNullOrEmpty(value))
            {
                result = new Nullable<T>();

                return true;
            }

            result = default(T);
            try
            {
                IConvertible convertibleString = (IConvertible)value;
                result = new Nullable<T>((T)convertibleString.ToType(typeof(T), System.Globalization.CultureInfo.CurrentCulture));
            }
            catch(InvalidCastException)
            {
                return false;
            }
            catch (FormatException)
            {
                return false;
            }

           return true;
        }

These were the basic test cases I used.

        string parseOne = "1";
        int? resultOne;
        bool successOne = parseOne.TryParseStruct<int>(out resultOne);
        Assert.IsTrue(successOne);
        Assert.AreEqual(1, resultOne);

        string parseEmpty = string.Empty;
        int? resultEmpty;
        bool successEmpty = parseEmpty.TryParseStruct<int>(out resultEmpty);
        Assert.IsTrue(successEmpty);
        Assert.IsFalse(resultEmpty.HasValue);

        string parseNull = null;
        int? resultNull;
        bool successNull = parseNull.TryParseStruct<int>(out resultNull);
        Assert.IsTrue(successNull);
        Assert.IsFalse(resultNull.HasValue);

        string parseInvalid = "FooBar";
        int? resultInvalid;
        bool successInvalid = parseInvalid.TryParseStruct<int>(out resultInvalid);
        Assert.IsFalse(successInvalid);
Bearish answered 8/4, 2010 at 21:30 Comment(0)
M
2

I'm more interested in knowing if there is a built-in framework method that will parse directly into a nullable int?

There isn't.

Mumford answered 28/10, 2008 at 1:31 Comment(1)
Would you consider this a direct approach? https://mcmap.net/q/92671/-how-to-parse-a-string-into-a-nullable-intOverflight
B
2

This solution is generic without reflection overhead.

public static Nullable<T> ParseNullable<T>(string s, Func<string, T> parser) where T : struct
{
    if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(s.Trim())) return null;
    else return parser(s);
}

static void Main(string[] args)
{
    Nullable<int> i = ParseNullable("-1", int.Parse);
    Nullable<float> dt = ParseNullable("3.14", float.Parse);
}
Businesslike answered 19/11, 2013 at 7:40 Comment(1)
I think you can replace IsNullOrEmpty with IsNullOrWhitespaceStasiastasis
V
1

I found and adapted some code for a Generic NullableParser class. The full code is on my blog Nullable TryParse

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
namespace SomeNamespace
{
    /// <summary>
    /// A parser for nullable types. Will return null when parsing fails.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    ///
    public static class NullableParser<T> where T : struct
    {
        public delegate bool TryParseDelegate(string s, out T result);
        /// <summary>
        /// A generic Nullable Parser. Supports parsing of all types that implements the tryParse method;
        /// </summary>
        /// <param name="text">Text to be parsed</param>
        /// <param name="result">Value is true for parse succeeded</param>
        /// <returns>bool</returns>
        public static bool TryParse(string s, out Nullable<T> result)
        {
            bool success = false;
            try
            {
                if (string.IsNullOrEmpty(s))
                {
                    result = null;
                    success = true;
                }
                else
                {
                    IConvertible convertableString = s as IConvertible;
                    if (convertableString != null)
                    {
                        result = new Nullable<T>((T)convertableString.ToType(typeof(T),
                            CultureInfo.CurrentCulture));
                        success = true;
                    }
                    else
                    {
                        success = false;
                        result = null;
                    }
                }
            }
            catch
            {
                success = false;
                result = null;
            }
            return success;
        }
    }
}
Vikkivikky answered 23/10, 2009 at 13:20 Comment(2)
404 - not found. it's not a good practice just to give a linkCrine
sorry about that @Crine update with full code. Better late than never :)Vikkivikky
T
1

I felt I should share mine which is a bit more generic.

Usage:

var result = "123".ParseBy(int.Parse);

var result2 = "123".ParseBy<int>(int.TryParse);

Solution:

public static class NullableParse
{
    public static Nullable<T> ParseBy<T>(this string input, Func<string, T> parser)
        where T : struct
    {
        try
        {
            return parser(input);
        }
        catch (Exception exc)
        {
            return null;
        }
    }

    public delegate bool TryParseDelegate<T>(string input, out T result);

    public static Nullable<T> ParseBy<T>(this string input, TryParseDelegate<T> parser)
        where T : struct
    {
        T t;
        if (parser(input, out t)) return t;
        return null;
    }
}

First version is a slower since it requires a try-catch but it looks cleaner. If it won't be called many times with invalid strings, it is not that important. If performance is an issue, please note that when using TryParse methods, you need to specify the type parameter of ParseBy as it can not be inferred by the compiler. I also had to define a delegate as out keyword can not be used within Func<>, but at least this time compiler does not require an explicit instance.

Finally, you can use it with other structs as well, i.e. decimal, DateTime, Guid, etc.

Telluric answered 24/3, 2011 at 13:54 Comment(0)
M
1
    public static void Main(string[] args)
    {

        var myString = "abc";

        int? myInt = ParseOnlyInt(myString);
        // null

        myString = "1234";

        myInt = ParseOnlyInt(myString);
        // 1234
    }
    private static int? ParseOnlyInt(string s)
    {
        return int.TryParse(s, out var i) ? i : (int?)null;
    }
Mane answered 8/10, 2015 at 17:32 Comment(1)
if myString is non-numeric, int.Parse throws an exception, which is not the same as returning null.Perhaps
C
0

You should never use an exception if you don't have to - the overhead is horrible.

The variations on TryParse solve the problem - if you want to get creative (to make your code look more elegant) you could probably do something with an extension method in 3.5 but the code would be more or less the same.

Camire answered 5/9, 2008 at 10:58 Comment(0)
J
0

Using delegates, the following code is able to provide reusability if you find yourself needing the nullable parsing for more than one structure type. I've shown both the .Parse() and .TryParse() versions here.

This is an example usage:

NullableParser.TryParseInt(ViewState["Id"] as string);

And here is the code that gets you there...

public class NullableParser
  {
    public delegate T ParseDelegate<T>(string input) where T : struct;
    public delegate bool TryParseDelegate<T>(string input, out T outtie) where T : struct;
    private static T? Parse<T>(string input, ParseDelegate<T> DelegateTheParse) where T : struct
    {
      if (string.IsNullOrEmpty(input)) return null;
      return DelegateTheParse(input);
    }
    private static T? TryParse<T>(string input, TryParseDelegate<T> DelegateTheTryParse) where T : struct
    {
      T x;
      if (DelegateTheTryParse(input, out x)) return x;
      return null;
    }
    public static int? ParseInt(string input)
    {
      return Parse<int>(input, new ParseDelegate<int>(int.Parse));
    }
    public static int? TryParseInt(string input)
    {
      return TryParse<int>(input, new TryParseDelegate<int>(int.TryParse));
    }
    public static bool? TryParseBool(string input)
    {
      return TryParse<bool>(input, new TryParseDelegate<bool>(bool.TryParse));
    }
    public static DateTime? TryParseDateTime(string input)
    {
      return TryParse<DateTime>(input, new TryParseDelegate<DateTime>(DateTime.TryParse));
    }
  }
Jarad answered 7/9, 2009 at 21:51 Comment(0)
N
0

I've come up with this one, which has satisfied my requirements (I wanted my extension method to emulate as close as possible the return of the framework's TryParse, but without try{} catch{} blocks and without the compiler complaining about inferring a nullable type within the framework method)

private static bool TryParseNullableInt(this string s, out int? result)
{
    int i;
    result = int.TryParse(s, out i) ? (int?)i : null;
    return result != null;
}
Nominalism answered 20/3, 2015 at 15:1 Comment(0)
B
0

I suggest code bellow. You may work with exception, when convert error occured.

public static class Utils {      
public static bool TryParse<Tin, Tout>(this Tin obj, Func<Tin, Tout> onConvert, Action<Tout> onFill, Action<Exception> onError) {
  Tout value = default(Tout);
  bool ret = true;
  try {
    value = onConvert(obj);
  }
  catch (Exception exc) {
    onError(exc);
    ret = false;
  }
  if (ret)
    onFill(value);
  return ret;
}

public static bool TryParse(this string str, Action<int?> onFill, Action<Exception> onError) {
  return Utils.TryParse(str
    , s => string.IsNullOrEmpty(s) ? null : (int?)int.Parse(s)
    , onFill
    , onError);
}
public static bool TryParse(this string str, Action<int> onFill, Action<Exception> onError) {
  return Utils.TryParse(str
    , s => int.Parse(s)
    , onFill
    , onError);
}
}

Use this extension method in code (fill int? Age property of a person class):

string ageStr = AgeTextBox.Text;
Utils.TryParse(ageStr, i => person.Age = i, exc => { MessageBox.Show(exc.Message); });

OR

AgeTextBox.Text.TryParse(i => person.Age = i, exc => { MessageBox.Show(exc.Message); });
Batik answered 10/11, 2015 at 10:47 Comment(0)
A
0

The cleaner way would be to write a separate function or extension method, but if you just want a one-liner:

string s;
int? i = s == null ? (int?)null : int.Parse(s);
Amperage answered 14/1, 2022 at 21:44 Comment(1)
What if the string isn't a number? Best approach is always use TryParse, like: int.TryParse(str, out var number) ? number : (int?)null;Rhys
H
-1

I realise this is an old topic, but can't you simply:

(Nullable<int>)int.Parse(stringVal);

?

Hughs answered 11/3, 2010 at 15:29 Comment(1)
You can, but then you'll get an exception if stringVal is in the wrong format. See the int.Parse documentation: msdn.microsoft.com/en-us/library/b3h1hf19.aspxVogel
E
-3

Maybe you can try this.

     string s1 = Console.ReadLine();
     int s2 = int.Parse(s1);
            
Enciso answered 17/10, 2023 at 22:40 Comment(1)
Your answer doesn't provide more information than the existing answers, I think you should read the help center for answers, especially How to answer? and Reasons leading to answer deletionVere

© 2022 - 2024 — McMap. All rights reserved.