调试LINQ查询

时间:2009-06-04 20:04:22

标签: c# linq debugging

我们最近在LINQ上做了很多工作,主要是在LINQ-to-Objects意义上。不幸的是,我们的一些查询可能有点复杂,特别是当它们开始涉及组合的多个序列时。当你得到的问题看起来很像时,很难确切知道发生了什么:

IEnumerable<LongType> myCompanies =       relevantBusiness.Children_Companies
            .Select(ca => ca.PR_ContractItemId)
            .Distinct()
            .Select(id => new ContractedItem(id))
            .Select(ci => ci.PR_ContractPcrId)
            .Distinct()
            .Select(id => new ContractedProdCompReg(id))
            .Select(cpcr => cpcr.PR_CompanyId)
            .Distinct();

var currentNewItems = myCompanies 
                .Where(currentCompanyId => !currentLic.Children_Appointments.Select(app => app.PR_CompanyId).Any(item => item == currentCompanyId))
                .Select(currentId => new AppointmentStub(currentLic, currentId))
                .Where(currentStub=>!existingItems.Any(existing=>existing.IsMatch(currentStub)));


Items = existingItems.Union(newItems).ToList();

等等...

即使您进行调试,也很难分辨谁在做什么以及何时做什么。如果没有无偿地在序列上调用“ToList”来获取我可以更容易检查的东西,是否有人对如何调试“复杂”LINQ有任何好的建议?

7 个答案:

答案 0 :(得分:15)

这样的查询似乎向我表明,你在选择合适的数据结构方面做得不好,或者在封装和分离任务方面做得很好。我建议看一看并分解它。

一般来说,如果我想调试一个显然不正确的LINQ查询,我会将其分解为子查询并在调试器中一次一个地检查结果。

答案 1 :(得分:14)

我知道我的回答“有点”迟到了,但我必须分享一下:

刚刚发现了 LinqPad ,这令人惊叹(更不用说免费)了。
无法相信我在不知道这个工具的情况下写了很长时间。

据我了解,这是O'Reilly "C# 3.0 in a Nutshell""C# 4.0 in a Nutshell"的作者(s?)的作品。

答案 2 :(得分:8)

当我最近环顾​​四周寻找同一个问题的答案时,我发现了一些有趣的提示,但是没有一个有凝聚力的叙述真的在回答这个问题。所以我自己写了一篇,它刚刚发布在Simple-Talk.com(LINQ Secrets Revealed: Chaining and Debugging)上。您可能需要注册才能阅读该文章(网站似乎在最近几天经历了一些变化)所以这里是文章的重点:

(1)在LINQPad中:使用其非凡的Dump()方法。您可以在LINQ链中的一个或多个点注入它,以便以清晰,清晰的方式显示您的数据。

(2)在Visual Studio中:在LINQ链的中间嵌入nop语句,以便设置断点。请注意,return语句必须在其自己的行上才能在Visual Studio中设置断点。 (感谢Eric White的博客文章Debugging LINQ Queries获取此提示。)

.Select(z =>
{return z;}
)

(3)在Visual Studio中:注入对我文章中提供的Dump()扩展方法的调用以允许记录。我在他的内容文章LINQ to Objects – Debugging中开始使用Bart De Smet的Watch()方法,并添加了一些标签和颜色以增强可视化,但与LINQPad的转储输出相比仍然相形见绌。

(4)最后,(是的,我迷恋于LINQPad的Dump方法!)将LINQPad的可视化与Robert Ivanc的LINQPad Visualizer加载项一起带入Visual Studio。不是一个完美的解决方案(VS2010还没有支持,要求类可序列化,一些渲染问题)但它非常有用。

2016.12.01更新

刚刚发布在Simple-Talk.com上的是上述文章的续集:LINQ Debugging and Visualization。本文全面介绍了Visual Studio 2015的OzCode扩展的新LINQ调试功能.OzCode最终使LINQ调试变得简单而强大。 (而且,不,我为OzCode工作: - )。

答案 3 :(得分:4)

我所知道的工具中没有构建。您可以做的最好的事情是在多个子查询中拆分查询并在调试时评估这些子查询。一个好的第三方工具是LINQPad

答案 4 :(得分:3)

This blog post有一些非常有前途的技术可以调试LINQ to Objects。

答案 5 :(得分:2)

马苹果!

Resharper(我喜欢)建议我改变这个

foreach (BomObservation initialObservation in initialObservations)
{
    if(initialObservation.IsValid() && !initialObservation.IsStationOnly)
        mappableObservations.Add(initialObservation);
}

到这个

initialObservations.Where(observation => observation.IsValid() && !observation.IsStationOnly).ToList();

它是否性感而且时尚,但是通过它并调试它?你不能这样做。我要回到这个时候了。

我也喜欢LinqPad而且我认为Linq在'一个戒指来统治他们'方面非常棒,但在这种情况下我会失去一些东西。

答案 6 :(得分:2)

我知道这是一个老问题,但是我发现其他解决方案可能对某人有用。在调试LINQ查询时,我一直在同一个问题上挣扎。有两种调试它们的好方法。

一种方法:将lambda表达式更改为body表达式。这使您可以在内部放置断点。您也可以在这些断点上单击鼠标右键来设置一些条件,以便为您提供很多可能性。示例:

// Instead of this:
var names = new List<string> { "Anna", "Tom", "Jerry" };
var namesLength = names.Select(name => name.Length);

// Use this:
var names = new List<string> { "Anna", "Tom", "Jerry" };
var namesLength = names.Select(name =>
{
    return name.Length; // Set breakpoint here
});

另一种方法:在Visual Studio中使用快速监视。怎么样?在上面的示例中,在LINQ查询所在的位置放置一个断点。当代码停止时,用鼠标选择整个LINQ查询,右键单击它,然后选择Quick Watch...。它使用程序中的实际数据生成您在其中进行的任何查询的结果。它也支持IntelliSense。 提示:通常,将.ToList()放在快速监视的查​​询末尾以查看结果通常是有用的。