我喜欢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循环,然后调试它们,但是有更好的方法吗?
答案 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。
您可以通过调查传递给 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
一次,每个值只被解析一次。