我想在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?


当前回答

我建议代码如下。当转换错误发生时,您可以例外地工作。

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

在代码中使用此扩展方法(fill int?一个人类的年龄属性):

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

其他回答

格伦·斯拉文:我更想知道是否 有一个内置的框架方法 这将直接解析为 nullable int ?

如果值是有效的,如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?

没有。

以下代码适用于任何结构类型。它基于来自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);
    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;
    }

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

我遇到了这个问题,我最终得到了这个(毕竟,一个if和2返回是如此冗长!):

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

更严肃的一点是,尽量不要把int (c#关键字)和Int32 (. net Framework BCL类型)混在一起——尽管它可以工作,但它只会让代码看起来很乱。