基于每个元素调试LINQ

时间:2013-05-01 13:03:54

标签: c# linq debugging visual-studio-2012

我喜欢LINQ语句的表达语法和其他方便的功能。但是,我发现有时调试它们非常麻烦。具体来说,当我在集合上运行LINQ语句并且集合中的一个元素导致异常时,如何确定问题输入是什么以及问题来自何处?

想象一下,我有一个包含1000个实数的文本文件:

0.46578
12.314213
1.444876
...

我正在将其作为List<string>阅读并将其加载到更具体的数据结构中:

var file_contents = File.ReadAllLines("myfile.txt");
var data = file_contents.Select(s => double.Parse(s));

现在,对于这个特定的输入,我没有仔细查看它,结果显示第876行包含(显示的行号):

875    5.56786450
876    Error: Could not calculate value.
878    0.0316213

无论出于何种原因(可能是由发生故障的脚本生成的文件)。我的LINQ方法链当然会引发异常。问题是,我如何计算列表中的哪个元素导致异常,以及它的值是什么?

澄清一下,如果我使用了for循环:

var data = new List<double>();
foreach(var row in file_contents)
{
    var d = double.Parse(row);
    data.Add(d);
}

然后异常会突出显示调用double.Parse的字符串,我可以将鼠标移到row以轻松查看问题输入是什么。

当然,我可以使用Resharper将我的LINQ语句转换为for循环,然后调试它们,但是有更好的方法吗?

5 个答案:

答案 0 :(得分:3)

在lambda函数上放置条件断点,其中条件为s.StartsWith(“5.56”)。你只需要将光标放在lambda上并按F9即可。假设你正在使用visual studio。

答案 1 :(得分:2)

var data = file_contents.Select(s => {
    try
    {
       return double.Parse(s);

    }
    catch
    {
       throw; //breakpoint?
    }
});

答案 2 :(得分:2)

免责声明:我为OzCode工作

使用Visual Studio无法进行LINQ调试。我建议你尝试使用OzCode。

这是您的代码在调试时看到的内容(第6项中的异常)。 Debugging LINQ exception

您可以通过调查传递给 Select 子句的项目来判断导致异常的项目 - 并且由于最后一项触发了异常 - 因此很容易找到有问题的值。

如果您有兴趣可以试试OzCode的LINQ调试 - 我们刚开始EAP

答案 3 :(得分:0)

我会亲自使用tryparse。

        var data = new List<string>
            {
                "0.46578",
                "12.314213",
                "Error: Could not calculate value.",
                "1.444876",
            };
        double d;
        var good = data.Where(s => Double.TryParse(s, out d)).Select(Double.Parse);
        var bad = data.Where(s => !Double.TryParse(s, out d)).Select(x => new
            {
                key = data.IndexOf(x),
                value = x
            }).ToDictionary(x => x.key, x => x.value);


        textBox1.AppendTextAddNewLine("Good Data:");
        WriteDataToTextBox(good);

        textBox1.AppendTextAddNewLine(String.Format("{0}{0}Bad Data:", Environment.NewLine));
        WriteDataToTextBox(bad);

AppendTextAddNewLine只是我为我的小概念验证测试程序编写的扩展方法

    public static void AppendTextAddNewLine(this TextBox textBox, string textToAppend)
    {
        textBox.AppendText(textToAppend + Environment.NewLine);
    }

修改

WriteDataToTextbox是一种将IEnumerble<T>写入文本框的通用方法。

    void WriteDataToTextBox<T>(IEnumerable<T> data )
    {
        foreach (var row in data)
        {
            textBox1.AppendTextAddNewLine(row.ToString());
        }
    }

忘记将输出放在这里,所以我想我应该这样做。它显示了导致问题的错误数据索引和数据本身。

Good Data:
0.46578
12.314213
1.444876


Bad Data:
[2, Error: Could not calculate value.]

答案 4 :(得分:0)

我不确定你为什么不喜欢这里的foreach循环。 LINQ无论如何都在内部使用它,正如你已经意识到使用LINQ和调试有一些优点和缺点是缺点。

我可能会将LINQ与foreach混合使用,最后会有以下内容:

// read all lines from file //
var file_contents = File.ReadAllLines("myfile.txt");

// set initial data list length to number of lines for better performance
var data = new List<double>(file_contents.Length);

// list for incorrect line numbers
var incorrectRows = new List<int>();

foreach (var x in file_contents.Select((s, i) => new {s, i}))
{
    // x.s - line string
    // x.i - line number

    double value;
    if (double.TryParse(x.s, out value))
        data.Add(value);        // add value, which was OK
    else
        incorrectRows.Add(x.i); // add index of incorrect value
}

这样可以防止出现异常,并为您提供所有不正确值的行号。它也只迭代file_contents一次,每个值只被解析一次。