如何将字符串解析为可为null的int


300

我想在C#中将字符串解析为可为null的int。即。我想找回字符串的int值,如果无法解析,则返回null。

我有点希望这能起作用

int? val = stringVal as int?;

但这是行不通的,所以我现在的方式是编写此扩展方法

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

有更好的方法吗?

编辑: 感谢您的TryParse建议,我的确知道这一点,但效果差不多。我更想知道是否有一个内置的框架方法可以直接解析为可为null的int?


1
您可以使用string.IsNullOrEmpty(value)来使if行更加清晰。
Özgür的卡普兰

Answers:


352

int.TryParse 可能有点容易:

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

编辑 @Glenn int.TryParse已“内置到框架中”。它int.Parse字符串解析为int的方法。


82
少一行:返回Int32.TryParse(s,out i)吗?我:空;
克里斯·谢特

2
“ a”将返回null,但不是int且应引发异常
Arsen Mkrtchyan

54
@Chris,编译器不喜欢您的内联if语句(这些类型不兼容:'int':'null')。我必须将其修改为:返回Int32.TryParse(s,输出i)?(int?)i:null;
death_au 2012年

8
Int32只是int的别名。我将使用int.TryParse来保持对齐使用的类型。如果/当使用int表示不同的位长整数(已发生)时,Int32将不会与int对齐。
理查德·科莱特

4
返回int.TryParse(s,out i)吗?(int?)i:null;
Nick Spreitzer 2015年

177

您可以使用条件运算符和可以强制转换的事实,在一行中完成此操作 null转换为可为null的类型(两行,如果您没有预先存在的int,则可以重用作为)的输出,而只需一行即可TryParse

C#7之前的版本:

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

使用C#7的更新语法,该语法允许您在方法调用中声明输出变量,这变得更加简单。

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

4
我认为,这取决于您对条件运算符的看法。我的思维模式是,对于if-else等效项,它几乎是语法糖,在这种情况下,我的版本和Matt的版本几乎完全相同,他的含义更加明确,我的写作更有意义。
McKenzieG1 2010年

11
这里没有评估顺序的副作用。所有步骤都是明确排序和正确的。
乔恩·汉娜

22
返回int.TryParse(val, out i) ? i : default(int?);
Bart Calixto

7
@Bart的“答案”是最好的!
Andre Figueiredo

4
现在在C#6中,它可以是一行!Int32.TryParse(stringVal,var tempVal)吗?tempVal:(int?)null;
MerickOWA

34

[ 根据@sblom的建议更新为使用现代C#]

我遇到了这个问题,最终遇到了这个问题(毕竟,an if和2 returns太难了!):

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

更严重的是,请不要将intC#关键字与Int32.NET Framework BCL类型与混合使用-尽管它可以工作,但只会使代码看起来混乱。


3
不太确定这是否会转化为编译后性能更好的东西
BuZz 2013年

1
在C#7中更加简洁:删除该int i;行,然后继续return int.TryParse (val, out var i) ? (int?) i : null;
blom '17

2
所以为了完整性;-)int? ParseNInt (string val) => int.TryParse (val, out var i) ? (int?) i : null;
Duckboy

使用C#6可以减少到1行:return int.TryParse(value,out var result)?结果:(int?)null;
MeanGreen

16

格伦·斯拉文(Glenn Slaven):我更想知道是否有内置的框架方法可以直接解析为可为null的int?

如果值像null或空字符串一样有效,则有一种方法可以直接解析为可为null的int(而不仅仅是int),但是会为无效值抛出异常,因此您需要捕获该异常并返回默认值对于这些情况:

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

此方法仍可用于不可为空的解析以及可为空的解析:

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%");

注意:转换器上有一个IsValid方法,可以用来代替捕获异常(如果发生异常,抛出异常会导致不必要的开销)。不幸的是,它仅适用于.NET 4,但是仍然存在一个问题,即在验证正确的DateTime格式时,它不检查您的语言环境,请参见Bug 93559


我测试了它的整数,它比int.TryParse((string)value,out var result)慢很多?结果:default(int?);
Wouter

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

资料来源:


这怎么工作?Tryparse将不起作用或无法为空,并且示例中的f必须为可为空。
约翰·洛德

请您能说明您的意思吗@JohnLord
Jaa H

tryparse期望放入一个不可为空的变量中,所以您的default(int?)是否会强制var为可为空?
John Lord

@JohnLord也许这可以帮助您了解stackoverflow.com/questions/3632918/…
Jaa H

9

旧主题,但是如何:

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

我更喜欢这样做,因为它要求解析null,TryParse版本不会在例如ToNullableInt32(XXX)上引发错误。这可能会导致不必要的无提示错误。


1
正是这一点-如果无法将字符串解析为int,则应返回null,而不抛出异常。
svick 2011年

1
如果value是非数字值,则int.Parse引发异常,该异常与返回null相同。

8

尝试这个:

public static int? ParseNullableInt(this string value)
{
    int intValue;
    if (int.TryParse(value, out intValue))
        return intValue;
    return null;
}

5

我觉得我的解决方案是一个非常干净而且不错的解决方案:

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

当然,这是一个通用解决方案,仅要求generics参数具有静态方法“ Parse(string)”。这适用于数字,布尔值,日期时间等。


5

您可能会忘记所有其他答案-有一个很好的通用解决方案:http : //cleansharp.de/wordpress/2011/05/generischer-typeconverter/

这使您可以编写非常干净的代码,如下所示:

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

并且:

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();

1
这确实非常有用。在我看来,这应该在标准c#库中,因为转换在每个程序中都很常见;)
BigChief 2013年

这非常好且有用,但是我可能会补充说,当需要对大量项目中的每个元素进行转换时,它非常慢。我已经测试了20000个项目:通过使用这种方法,转换每个项目的8个属性最多需要1个小时才能完成整个集合。使用相同的样本数据,但使用Matt Hamilton的方法,只需几秒钟即可完成。
zed 2016年

3

以下内容适用于任何结构类型。它基于MSDN论坛中Matt Manela的代码。正如Murph指出的,与使用Types专用的TryParse方法相比,异常处理可能会很昂贵。

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

这些是我使用的基本测试用例。

        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);

3

我建议使用以下扩展方法将字符串解析为int值,并能够定义默认值,以防无法解析:

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();
        }

已经有很多甚至很高的评价了。您是否真的认为您的答案是必需的,并为此帖子增加了新的质量?
L. Guthardt '18

1
@ L.Guthardt是的,我是这样认为的。我认为我的答案带来了解决问题的更通用方法。谢谢。
Aleksandr Neizvestnyi

2

该解决方案是通用的,没有反射开销。

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);
}

我认为您可以替换IsNullOrEmptyIsNullOrWhitespace
NibblyPig,2016年


1

我觉得我应该分享我的,这是更通用的。

用法:

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

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

解:

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

第一个版本较慢,因为它需要尝试捕获,但看起来更干净。如果不会用无效的字符串多次调用它,那不是很重要。如果性能是一个问题,请注意,在使用TryParse方法时,您需要指定ParseBy的类型参数,因为编译器无法推断出它。我还必须定义一个委托,因为out关键字不能在Func <>中使用,但是至少这次,编译器不需要显式实例。

最后,您还可以将其与其他结构一起使用,即十进制,DateTime,Guid等。


1

我为Generic NullableParser类找到并改编了一些代码。完整的代码在我的博客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;
        }
    }
}

1
404-找不到。仅仅给出链接不是一个好习惯
肮脏的流程

抱歉@ Dirty-flow用完整代码进行更新。迟到总比没有好:)
约翰·达芬因

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

1
如果myString为非数字类型,则int.Parse会引发异常,该异常与返回null相同。
2016年

0

你应该永远开销是可怕的-如果你没有使用一个例外。

TryParse的变体解决了这个问题-如果您想发挥创造力(使您的代码看起来更优雅),则可以使用3.5中的扩展方法执行某些操作,但是代码大致相同。


0

使用委托,如果发现自己需要多个结构类型的可空分析,则以下代码可以提供可重用性。我在这里显示了.Parse()和.TryParse()版本。

这是一个示例用法:

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

这是让您到达那里的代码...

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));
    }
  }


0

我提出了一个满足我要求的程序(我希望我的扩展方法尽可能地模仿框架的TryParse的返回值,但是没有try {} catch {}块,并且编译器没有抱怨要推断一个框架方法内的可为null的类型)

private static bool TryParseNullableInt(this string s, out int? result)
{
    int i;
    result = int.TryParse(s, out i) ? (int?)i : null;
    return result != null;
}

0

我建议下面的代码。发生转换错误时,您可能会例外处理。

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);
}
}

在代码中使用此扩展方法(请填写int?person类的Age属性):

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

要么

AgeTextBox.Text.TryParse(i => person.Age = i, exc => { MessageBox.Show(exc.Message); });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.