如果string可解析为int,则选择解析的int

Ben*_*key 49 c# linq int

所以我有一个IEnumerable<string>可以包含可以解析int为的值,以及不能的值.

如您所知,Int32.Parse如果字符串无法更改为int,则抛出异常,同时Int32.TryParse可用于检查并查看是否可以在不处理异常的情况下进行转换.

所以我想使用LINQ查询来解析那些可以解析为int的字符串,而不会抛出异常.我有一个解决方案,但希望社区提出有关这是否是最佳方法的建议.

这就是我所拥有的:

int asInt = 0;
var ints = from str in strings
           where Int32.TryParse(str, out asInt)
           select Int32.Parse(str);
Run Code Online (Sandbox Code Playgroud)

所以你可以看到,我正在使用它asInt作为调用的临时空间TryParse,只是为了确定是否TryParse会成功(返回bool).然后,在投影中,我实际上正在执行解析.那感觉很难看.

这是使用LINQ过滤单行中的可解析值的最佳方法吗?

Jon*_*eet 83

在查询语法中很难做到这一点,但在lambda语法中它并不算太糟糕:

var ints = strings.Select(str => {
                             int value;
                             bool success = int.TryParse(str, out value);
                             return new { value, success };
                         })
                  .Where(pair => pair.success)
                  .Select(pair => pair.value);
Run Code Online (Sandbox Code Playgroud)

或者,您可能会发现值得编写一个返回以下内容的方法int?:

public static int? NullableTryParseInt32(string text)
{
    int value;
    return int.TryParse(text, out value) ? (int?) value : null;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用:

var ints = from str in strings
           let nullable = NullableTryParseInt32(str)
           where nullable != null
           select nullable.Value;
Run Code Online (Sandbox Code Playgroud)

  • 我希望框架有一个int?这种情况的int.TryParse(string)方法 (3认同)
  • @byte:不同之处在于你的版本在触摸另一个变量时会产生副作用......所以你不能并行运行它. (2认同)

Joe*_*nos 13

它仍然是两个代码行,但你可以稍微缩短你的原始代码:

int asInt = 0;
var ints = from str in strings
           where Int32.TryParse(str, out asInt)
           select asInt;
Run Code Online (Sandbox Code Playgroud)

由于TryParse已经在select时运行asInt,因此填充变量,因此您可以将其用作返回值 - 您无需再次解析它.

  • 这不是最佳实践。asInt 初始化的时刻是不可预测的,因为它将在执行此 LINQ 查询时发生(可能在不同方法的其他地方)。因此,您不应依赖在此查询后初始化的 asInt。最好按照乔恩在他的回答中所展示的那样去做。 (2认同)

Kel*_*ron 6

如果你不介意你的同事在停车场跳你,有一种方法可以用一个真正的linq(没有分号)来做到这一点....

strings.Select<string, Func<int,int?>>(s => (n) => int.TryParse(s, out n) ? (int?)n : (int?)null ).Where(? => ?(0) != null).Select(? => ?(0).Value);
Run Code Online (Sandbox Code Playgroud)

这是不切实际的,但在一个声明中这样做是一个非常有趣的挑战.


dri*_*iis 5

我可能在某个地方有这个小实用方法(我实际上在我当前的代码库中这样做了 :-))

public static class SafeConvert
{
    public static int? ToInt32(string value) 
    {
        int n;
        if (!Int32.TryParse(value, out n))
            return null;
        return n;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你使用这个更干净的 LINQ 语句:

from str in strings
let number = SafeConvert.ToInt32(str)
where number != null
select number.Value;
Run Code Online (Sandbox Code Playgroud)


Gil*_*een 5

我同意使用额外的变量感觉很丑

根据Jon 的回答更新到 C# 7.0 解决方案,我们可以使用新var out功能:(不会短很多,但不需要内部作用域或查询外临时变量

var result = strings.Select(s => new { Success = int.TryParse(s, out var value), value })
                    .Where(pair => pair.Success)
                    .Select(pair => pair.value);
Run Code Online (Sandbox Code Playgroud)

以及命名元组:

var result = strings.Select(s => (int.TryParse(s, out var value), value))
                    .Where(pair => pair.Item1)
                    .Select(pair => pair.value);
Run Code Online (Sandbox Code Playgroud)

或者,如果建议在查询语法中使用它的方法:

public static int? NullableTryParseInt32(string text)
{
    return int.TryParse(text, out var value) ? (int?)value : null;
}
Run Code Online (Sandbox Code Playgroud)

我还想建议一种无需额外方法的查询语法,但如以下链接中所述,out varc# 7.0 不支持并导致编译错误:

查询子句中不允许使用 Out 变量和模式变量声明

链接:查询表达式中的表达式变量


通过这是一项 C# 7.0 功能,人们可以让它在早期的 .NET 版本上工作: