【问题标题】:using out type in linq [duplicate]在linq中使用out类型[重复]
【发布时间】:2013-01-05 17:28:14
【问题描述】:

可能重复:
LINQ: Select parsed int, if string was parseable to int

这可能是一个基本问题,但我想不出解决办法。我有一个字符串数组,我试图用整数解析它们。正如预期的那样,我得到了格式异常。

我怎样才能跳过“3a”并继续解析剩余的数组并使用 Linq 将整数存储到输出中。?这是更好的方法还是不做的做法?请说明在这种情况下如何使用 TryParse

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] values = { "1", "2", "3a","4" };
            List<int> output = new List<int>();

            try{
                output = values.Select(i => int.Parse(i)).ToList<int>();
            }
            catch(FormatException)
            {
                foreach (int i in output)
                    Console.WriteLine(i);
            }

            foreach (int i in output)
                Console.WriteLine(i);

            Console.ReadLine();
        }

    }
}

【问题讨论】:

    标签: c# .net linq


    【解决方案1】:

    你可以使用int.TryParse

    string[] values = { "1", "2", "3a","4" };
    int i = int.MinValue;
    List<int> output = values.Where(s => int.TryParse(s, out i))
                             .Select(s => i)
                             .ToList();
    

    Demo

    但是,Eric Lippert would not be amused。因此,如果您不想(ab)使用副作用,这将是最佳实践方法:

    创建一个扩展方法,如:

    public static class NumericExtensions
    {
        public static int? TryGetInt(this string item)
        {
            int i;
            bool success = int.TryParse(item, out i);
            return success ? (int?)i : (int?)null;
        }
    }
    

    那么你就可以这样写了:

    List<int> output = values.Select(s => s.TryGetInt())
                 .Where(nullableInt => nullableInt.HasValue)
                 .Select(nullableInt => nullableInt.Value)
                 .ToList();
    

    【讨论】:

    • 这能保证工作吗?我认为在Select 读取第一个值之前,Where 不能用第二个值覆盖 i 没有技术原因。
    • @hvd:是的,至少在 Linq-To-Objects 中是这样。虽然我目前没有可用的链接。
    • @hvd:这个答案依赖于 LINQ to Objects 的实现细节“延迟执行”。在其当前实现中以及使用 LINQ to Objects 时,它可以保证工作。
    • 我在documentation中看到的只是“这个方法是通过延迟执行来实现的。立即返回值是一个对象,它存储了执行该操作所需的所有信息。查询表示在通过直接调用其 GetEnumerator 方法或使用 Visual C# 中的 foreach 或 Visual Basic 中的 For Each 枚举对象之前,不会执行此方法。"但这允许过滤器一次性评估所有记录,即使当前实现没有这样做。
    • 我最初对这段代码感到惊讶,但在稍微考虑一下“延迟执行”之后,我现在明白了。
    【解决方案2】:

    虽然我完全同意在 Tim Schmelter 的回答中使用 int.TryParse,但我认为他的回答依赖于未记录的实现细节,而更安全的替代方案可能是

    List<int> output =
        values
        .Select(s => {
            int i;
            return int.TryParse(s, out i) ? i : default(int?);
        })
        .Where(i => i != null)
        .Select(i => i.Value)
        .ToList();
    

    您也许可以将.Where(...).Select(...) 替换为.OfType&lt;int&gt;()

    您也可以将第一个 .Select(...) lambda 与明确的可重用函数放在一起:

    int? MyTryParse(string s)
    {
        int i;
        return int.TryParse(s, out i) ? i : default(int?);
    }
    
    List<int> output =
        values
        .Select(MyTryParse)
        .Where(i => i != null)
        .Select(i => i.Value)
        .ToList();
    

    【讨论】:

    • 感谢您的回答。开始了解显式可重用函数
    【解决方案3】:

    来自Tim Schmelter 答案的linq 版本

            string[] values = { "1", "2", "3a", "4" };
            int i = int.MinValue;
            var output = (from c in values
                          where int.TryParse(c, out i) 
                          select c).Select(s => int.Parse(s)).ToList();
            foreach (var item in output)
            {
                Console.WriteLine(item.ToString());
            }
    

    【讨论】:

    • 创造性思维+1。 :) 只使用int.TryParse 的布尔结果,忽略它的输出参数,显然是正确的。
    • 我从先生那里得到了这个想法。 @Tim Schmelter,谢谢 :)
    • 感谢您的回答。教会了我一些东西。
    • linq 版本适合我们这样的初学者 :D
    • @spajce:我们都在使用 linq,您使用的是 query-,而我使用的是 method-synatx。除此之外,虽然它需要解析字符串两次,但这是个好主意。
    【解决方案4】:

    为什么要使用 LINQ?

    试试这个:

    foreach(string str in values)
    {
       int val;
       if(int.TryParse(str, out val))
       {
          output.Add(val);
       }
    }
    

    【讨论】:

    • 这可行,但想知道我的方法在 LINQ 中是否有效。感谢您的回答。
    • 并非所有解决方法都最好使用 LINQ。
    【解决方案5】:

    这个怎么样?受 Tim 的回答启发,但临时变量在循环内移动,因此它是并行安全的(假设字符串集合 values 是 ParallelEnumerable)。

    values.Select(s =>
        {int i; return int.TryParse(s, out i) ? (int?)i : null;})
        .Where(x=>x!=null).Select(x=>x.Value);
    

    所以给定["1", "two", "3"] 它返回[1,3]

    【讨论】:

    • 这也是我在回答中所做的,所以“LGTM”:)
    【解决方案6】:
    List<string> output = values.Where(v => Regex.Match(v, "^(0|[1-9][0-9]*)$").Success)
                                            .ToList();
    

    示例使用正则表达式进行更多控制,以指示哪些值被视为有效。

    【讨论】:

    • 这对我有帮助。但我想了解并了解如何在 LINQ 中使用 out 类型。非常感谢您的回答
    猜你喜欢
    • 2013-11-24
    • 1970-01-01
    • 2016-02-12
    • 1970-01-01
    • 2011-03-10
    • 2016-07-08
    • 1970-01-01
    • 2013-01-06
    • 1970-01-01
    相关资源
    最近更新 更多