如何调试LINQ语句
我有一个Linq to objects语句
var confirm = from l in lines.Lines where (l.LineNumber == startline.LineNumber) || (l.LineNumber == endline.LineNumber) select l;
确认对象在System.Linq.Enumerable.WhereListIterator`1.MoveNext()处返回"对象为空或者不是引用"。
如果查询结果为空,则只会返回一个空的枚举数。我知道,语句中没有空对象。是否可以单步执行LINQ语句以查看它的下落位置?
编辑当我说我知道没有空对象的事实时,事实证明我在撒谎:[,但是问题仍然存在,尽管我假设答案将是"你不能真的"
LINQPad是一个好主意,我用它来自学LINQ,但我可能会再次将其作为调试/斜杠和刻录样式工具来研究
解决方案
我不确定是否可以从VS进行调试,但是我发现LINQPad非常有用。它可以让我们转储LINQ查询的每个部分的结果。
检查异常堆栈跟踪,并查看所执行代码的最后一位。
从错误的外观来看,我建议我们看一下line.Lines并确保其枚举器已正确实现。我认为它不应该返回null。
哦,只需确保line和line.Lines对象不为null或者返回null。
我们应该能够在LINQ语句的where子句中的表达式上设置断点。
在此示例中,将光标放在代码的以下部分的任意位置:
(l.LineNumber == startline.LineNumber) || (l.LineNumber == endline.LineNumber)
然后按F9键或者使用菜单或者上下文菜单添加断点。
如果设置正确,则仅上述代码在编辑器中应具有断点格式,而不是整个LINQ语句。我们也可以在断点窗口中查看。
如果设置正确,则每次都会在实现查询的上述部分的函数处停止。
是的,确实可以在linq查询中途暂停执行。
使用lambda表达式将linq转换为查询样式,并插入Select语句,该语句在要调试的linq点之后的某处返回自身。一些示例代码将使其更加清晰-
var query = dataset.Tables[0].AsEnumerable() .Where (i=> i.Field<string>("Project").Contains("070932.01")) // .Select(i => // {return i;} // ) .Select (i=>i.Field<string>("City"));
然后取消注释行。确保{return i;}在其单独的行上,并在其中插入调试点。我们可以在冗长,复杂的linq查询中的任何时候放置此选择。
我写了一篇综合文章,针对这个问题,早在2010年就发布在Simple-Talk.com上(《 LINQ Secrets Revealed:Chaining and Debugging》):
我谈到LINQPad(如OwenP前面提到的)是Visual Studio外部的出色工具。特别注意其非凡的Dump()方法。我们可以在LINQ链中的一个或者多个点上注入此数据,以惊人的干净清晰的方式查看数据。尽管非常有用,但LINQPad在Visual Studio外部。因此,我还介绍了可在Visual Studio中使用的几种技术,因为有时将大量代码迁移到LINQPad上是不切实际的:
(1)注入对我在本文中介绍的Dump()扩展方法的调用,以允许进行日志记录。我从Bart De Smet的资料丰富的文章LINQ to Objects Debugging中开始使用Watch()方法,并添加了一些标签和颜色以增强可视化效果,尽管与LINQPad的Dump输出相比仍然显得苍白。
(2)使用Robert Ivanc的LINQPad Visualizer插件将LINQPad的可视化功能直接带入Visual Studio。不确定是否通过我的建议进行:-),但是在我撰写本文时给夫妇带来的不便现在在最新版本中得到了很好的解决。它具有完整的VS2010支持,并允许我们在调试时检查所需的任何对象。
(3)将nop语句嵌入LINQ链的中间,以便我们可以设置断点,如前面的Amazing Pete所述。
2016.12.01更新
我刚刚写了上一篇文章的续篇,标题为LINQ Debugging and Visualization(简单地讲LINQ调试和可视化),它揭示了真正的LINQ调试功能终于随着OzCode中即将发布的新功能进入了Visual Studio 2015. @Dror对这个问题的回答只显示了一点点,但我鼓励我们阅读我的新文章以获取深入的"如何做"。 (而且我不为OzCode工作。:-)