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

Posted

技术标签:

【中文标题】如何将字符串解析为可为空的 int【英文标题】:How to parse a string into a nullable int 【发布时间】:2010-09-07 21:16:28 【问题描述】:

我想在 C# 中将字符串解析为可为空的 int。 IE。如果无法解析,我想取回字符串的 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 的建议,我确实知道这一点,但结果大致相同。我更想知道是否有内置的框架方法可以直接解析为可为空的 int?

【问题讨论】:

您可以使用 string.IsNullOrEmpty(value) 使 if 行更清晰。 考虑使用泛型转换***.com/questions/773078/… 【参考方案1】:

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将字符串解析为整数的方法。

【讨论】:

少一行:return Int32.TryParse(s, out i) ?我:空; "a" 将返回 null,但它不是 int 并且应该抛出异常 @Chris,编译器不喜欢你的内联 if 语句(这些类型不兼容:'int':'null')。我不得不将其修改为:return Int32.TryParse(s, out i)? (int?)i : null; Int32 只是 int 的别名。我会使用 int.TryParse 来保持正在使用的类型对齐。如果/当 int 用于表示不同的位长整数(已经发生),Int32 将不会与 int 对齐。 返回 int.TryParse(s, out i) ? (int?)i : null;【参考方案2】:

您可以在一行中执行此操作,使用条件运算符以及您可以将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;

【讨论】:

我认为这取决于您对条件运算符的看法。我的心智模型是,它几乎是 if-else 等价物的语法糖,在这种情况下,我的版本和 Matt 的版本接近相同,他的版本更明确,我的 cmopact 更多。 这里没有评估顺序的副作用。所有步骤均已明确排序且正确。 返回int.TryParse(val, out i) ? i : default(int?); @Bart 的“答案”在这里是最好的! 现在在 C# 6 中,它可以是一行! Int32.TryParse(stringVal, out var tempVal) ? tempVal : (int?)null;【参考方案3】:

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

我遇到了这个问题,我最终解决了这个问题(毕竟,if 和 2 个returns 太啰嗦了!):

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

更严肃地说,尽量不要将 int(这是一个 C# 关键字)与 Int32(一种 .NET Framework BCL 类型)混用 - 虽然它可以工作,但它只会让代码看起来很乱。

【讨论】:

不太确定这是否真的会转化为编译后性能更好的任何东西 在 C# 7 中更简洁:删除 int i; 行并使用 return int.TryParse (val, out var i) ? (int?) i : null; 为了完整性 ;-) int? ParseNInt (string val) => int.TryParse (val, out var i) ? (int?) i : null; 使用 C# 6 这可以减少到 1 行: return int.TryParse(value, out var result) ?结果 : (int?)null;【参考方案4】:

C# >= 7.1

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

请参阅C# language versioning 以确定您的项目支持的语言版本

【讨论】:

这怎么可能? Tryparse 将不起作用或可为空变量,并且您的示例中的 f 必须是可为空的。 tryparse 期望被放入一个不可为空的变量中,所以你的 default(int?) 不会强制 var 可以为空吗?【参考方案5】:

Glenn Slaven:我更想知道是否 有一个内置的框架方法 这将直接解析为 可以为空的整数?

如果值像 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 方法,您可以使用它来代替捕获异常(如果预期,抛出的异常确实会导致 unnecessary overhead)。不幸的是,它仅从 .NET 4 开始有效,但仍然存在一个问题,即在验证正确的 DateTime 格式时它不会检查您的语言环境,请参阅bug 93559。

【讨论】:

我测试了这个整数,它比 int.TryParse((string)value, out var result) 慢很多?结果:默认(int?);【参考方案6】:

老话题,但是怎么样:

public static int? ParseToNullableInt(this string value)

     return String.IsNullOrEmpty(value) ? null : (int.Parse(value) as int?);

我更喜欢这个作为解析 null 的要求,TryParse 版本不会抛出错误,例如ToNullableInt32(XXX)。这可能会引入不必要的静默错误。

【讨论】:

这正是重点——如果字符串不能解析为int,它应该返回null,而不是抛出异常。 如果value是非数值型,int.Parse抛出异常,和返回null不一样。【参考方案7】:

试试这个:

public static int? ParseNullableInt(this string value)

    int intValue;
    if (int.TryParse(value, out intValue))
        return intValue;
    return null;

【讨论】:

【参考方案8】:

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

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;
    

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

【讨论】:

【参考方案9】:

您可以忘记所有其他答案 - 有一个很棒的通用解决方案: 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();

【讨论】:

这确实很有用。在我看来,这应该在标准 c# 库中,因为转换在每个程序中都很常见;) 这是非常好的和有用的,但我可以补充一点,当需要对大量项目中的每个元素进行转换时,它非常慢。我已经测试了 20000 个项目:通过使用这种方法,转换每个项目的 8 个属性需要长达 1 小时才能完成整个集合。使用相同的样本数据但使用Matt Hamilton's approach 只需几秒钟即可完成。【参考方案10】:

以下内容适用于任何结构类型。它基于Matt Manela from MSDN forums 的代码。正如 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);

【讨论】:

【参考方案11】:

我建议使用以下扩展方法将字符串解析为 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 是的,我想是的。正如我认为我的回答带来了更通用的方法来解决所描述的问题。谢谢。【参考方案12】:

我更想知道是否有一个内置的框架方法可以直接解析成一个可为空的 int?

没有。

【讨论】:

您认为这是一种直接的方法吗? ***.com/a/6474962/222748【参考方案13】:

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

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

【讨论】:

我觉得你可以把IsNullOrEmpty换成IsNullOrWhitespace【参考方案14】:

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

用法:

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;
    

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

最后,您也可以将其与其他结构一起使用,即十进制、日期时间、Guid 等。

【讨论】:

【参考方案15】:

我为 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;
        
    

【讨论】:

404 - 未找到。仅仅提供链接不是一个好习惯 对带有完整代码的@Dirty-flow 更新感到抱歉。迟到总比没有好:)【参考方案16】:
    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;
    

【讨论】:

如果myString为非数值型,int.Parse抛出异常,与返回null不同。【参考方案17】:

如果你不需要,你应该永远使用异常 - 开销太可怕了。

TryParse 的变体解决了这个问题 - 如果您想获得创意(使您的代码看起来更优雅),您可能可以使用 3.5 中的扩展方法做一些事情,但代码或多或少是相同的。

【讨论】:

【参考方案18】:

使用委托,如果您发现自己需要对多个结构类型进行可空解析,则以下代码能够提供可重用性。我在这里展示了 .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));
    
  

【讨论】:

【参考方案19】:

我知道这是一个老话题,但你不能简单地说:

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

?

【讨论】:

可以,但如果 stringVal 格式错误,则会出现异常。请参阅 int.Parse 文档:msdn.microsoft.com/en-us/library/b3h1hf19.aspx【参考方案20】:

我想出了这个,它满足了我的要求(我希望我的扩展方法尽可能地模拟框架的 TryParse 的返回,但没有 try catch 块并且没有编译器抱怨关于在框架方法中推断可空类型)

private static bool TryParseNullableInt(this string s, out int? result)

    int i;
    result = int.TryParse(s, out i) ? (int?)i : null;
    return result != null;

【讨论】:

【参考方案21】:

我建议下面的代码。当发生转换错误时,您可能会遇到异常。

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

【讨论】:

【参考方案22】:

更简洁的方法是编写一个单独的函数或扩展方法,但如果你只想要一个单行:

string s;
int? i = s == null ? (int?)null : int.Parse(s);

【讨论】:

如果字符串不是数字怎么办?最好的方法是始终使用 TryParse,例如:int.TryParse(str, out var number) ? number : (int?)null;

以上是关于如何将字符串解析为可为空的 int的主要内容,如果未能解决你的问题,请参考以下文章

为可为空的函数参数提供“null”时如何使用默认值?

如何将 int.TryParse 与可为空的 int 一起使用? [复制]

退出构造函数时,不可为空的属性必须包含非空值。考虑将属性声明为可为空

如何将 C# 可为空的 int 转换为 int

ORA-12704: 执行可为空的 NVARCHAR 的多行 INSERT 时字符集不匹配

在 JSON 文件中保存和加载可为空的字符串