C# 基于每个元素调试LINQ

C# 基于每个元素调试LINQ,c#,linq,debugging,visual-studio-2012,C#,Linq,Debugging,Visual Studio 2012,我喜欢LINQ语句的表达语法和其他方便的特性。然而,我发现有时调试它们非常麻烦。具体地说,当我对集合运行LINQ语句并且集合中的一个元素导致异常时,我如何确定问题输入是什么以及问题来自何处 假设我有一个包含1000个实数的文本文件: 0.46578 12.314213 1.444876 ... 我将此作为列表阅读,并将其加载到更具体的数据结构中: var file_contents = File.ReadAllLines("myfile.txt"); var data = file_conte

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

假设我有一个包含1000个实数的文本文件:

0.46578
12.314213
1.444876
...
我将此作为
列表阅读
,并将其加载到更具体的数据结构中:

var file_contents = File.ReadAllLines("myfile.txt");
var data = file_contents.Select(s => double.Parse(s));
现在,对于这个特定的输入,我没有仔细查看它,结果发现第876行包含(显示的行号):

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

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

var data = new List<double>();
foreach(var row in file_contents)
{
    var d = double.Parse(row);
    data.Add(d);
}
var data=newlist();
foreach(文件内容中的变量行)
{
var d=double.Parse(行);
数据.添加(d);
}
然后,异常将突出显示调用
double.Parse
的字符串,我将能够将鼠标悬停在
上,以轻松查看问题输入是什么


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

在lambda函数上放置一个条件断点,其中条件是s.StartsWith(“5.56”)。您只需要将光标放在lambda上,然后按F9。假设您使用的是visual studio。

我会亲自使用tryparse

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

    }
    catch
    {
       throw; //breakpoint?
    }
});
        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);
编辑

WriteDataTextBox是一种将
IEnumerble
写入文本框的通用方法

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

我不知道您为什么不喜欢这里的
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
}
//从文件中读取所有行//
var file_contents=file.ReadAllLines(“myfile.txt”);
//将初始数据列表长度设置为行数以获得更好的性能
var数据=新列表(文件内容.Length);
//列出不正确的行号
var incorrectRows=新列表();
foreach(文件中的varx_contents.Select((s,i)=>new{s,i}))
{
//x.s-行字符串
//x.i-线路编号
双重价值;
if(双色锥巴色(x.s,输出值))
data.Add(value);//Add value,这是可以的
其他的
incorrectRows.Add(x.i);//添加不正确值的索引
}
这将完全防止出现异常,并为所有不正确的值提供行号。它还只在
文件内容上迭代一次,每个值只被解析一次。

免责声明:我为OzCode工作

使用VisualStudio进行LINQ调试几乎是不可能的。我建议您尝试使用OzCode

这是调试代码时的外观(第6项中的异常)。

您可以通过调查传递给Select子句的项来判断是哪个项导致了异常,而且由于上一个项触发了异常,因此很容易找到有问题的值


如果您感兴趣,您可以尝试OzCode的LINQ调试-我们刚刚开始了一个

,非常感谢您的评论的建设性。既然你有更好的方法,请你发表自己的答案,这不是“你见过的最糟糕的LINQ使用情况”。这里的主要问题是,你的解决方案在
数据上迭代了
2+I
次,其中
I
是不正确的行数-
IndexOf
每次调用集合时都从头开始迭代集合。您还可以
Parse
每一行至少两次,其中大多数三次(两次
TryParse
和一次
Parse
以获得良好的值)。这不是很有效,是吗?我已经发布了我的答案,请随意批评!让我向您展示一下,当直接从您的注释(而非非非结构化部分)获取代码时,我将如何编写注释。“您的解决方案在数据上迭代了2+I次,其中I是不正确的行数-每次调用集合时,IndexOf都会从一开始就迭代集合。您还可以至少分析每一行两次,其中大多数是三次(两次TryParse和一次Parse以获得良好的值)。已经存在Select重载,并提供了一个索引..using.Select((s,I)=>我是“这是什么样的LINQ?EF还是LINQ到SQL?”?
    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.]
// 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
}