C# 基于每个元素调试LINQ
我喜欢LINQ语句的表达语法和其他方便的特性。然而,我发现有时调试它们非常麻烦。具体地说,当我对集合运行LINQ语句并且集合中的一个元素导致异常时,我如何确定问题输入是什么以及问题来自何处 假设我有一个包含1000个实数的文本文件: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
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
}