【问题标题】:How to debug LINQ result如何调试 LINQ 结果
【发布时间】:2012-07-13 03:19:39
【问题描述】:

我是 linq 的新手。所以有时只是不明白 linq 是如何工作的。所以VS2010 IDE中有任何工具或内置机制来详细调试linq执行。假设我有这个 linq 查询

var to_search = new[] { "Geo", "JCB" };

var result = from sr in list
             let w = to_search.FirstOrDefault(ts => sr.Title.ToLower().Contains(ts.ToLower()))
             where w != null
             let a = new {sr=sr, word=w.ToLower()}
             group a by a.word into g
             orderby g.Count() descending
             let sorted = g.OrderByDescending(a=> a.sr.Title.Select((c, i) => a.sr.Title.Substring(i)).Count(sub => sub.ToLower().StartsWith(a.word)))
             from a in sorted 
             select a.sr;

var completeList = result.Concat(list.Except(result));

如何详细调试上面的 linq 查询。请指导我。谢谢。

【问题讨论】:

  • 为什么不把它分解成小块并为每一块编写单元测试呢?然后给整体写个单元测试?
  • 调试 LINQ 结果的部分困难在于它将默认为 IEnumerable 并被延迟评估,因此传统的 VS IDE 调试工具只能帮助您到此为止。如果你想在 LINQ 中涂鸦并玩弄结果,我推荐 LINQPad。
  • LINQPad 如何帮助我调试结果。如何在那里设置断点。寻求建议。

标签: c# linq debugging linq-to-objects


【解决方案1】:

对于这个看似简单的问题,可以写很多东西!事实上,我已经在 Simple-Talk.com 上的文章LINQ Secrets Revealed: Chaining and Debugging 中详细写过。以下是其关键点的摘要:

  • 您可以使用调试器单步执行一些 LINQ 查询,但这取决于查询中表达式和语句的组成(因为您只能单步执行 语句)。
  • LINQ 方法链之所以起作用,是因为有一个基本规则:每个非终端 方法都将IEnumerable<T> 作为输入并返回IEnumerable<T> 作为输出。
  • 只要符合基本规则,您可以注入“no-op”语句来为您提供“垫脚石”。也就是说,意识到您始终可以将 .Select(z => z) 放入方法链中而不会产生任何后果,请使用它的变体:z => { return z; }
  • 您可以类似地注入诊断方法来提供输出,而不仅仅是提供潜在的断点。 LINQPad 是出色的暂存器,不仅适用于 LINQ,而且通常适用于 C#,它以其强大的 Dump() 方法提供了这一点。 Dump 是一个对象可视化工具,可提供复杂数据结构的惊人可视化。
  • 根据 Bart De Smet 在其内容丰富的文章 LINQ to Objects – Debugging 中的工作,您可以将 Dump 的简化风格带回到 Visual Studio 中——我提供了顶部提到的文章的附加代码。
  • 感谢 Robert Ivanc 对 LINQPad Visualizer 所做的工作,您甚至可以将 LINQPad 可视化工具带入 Visual Studio(尽管您需要为单个表达式手动启动它;您不能将其连接到 Dump() 方法)。李>

作为一个简单的例子,考虑这个简单的方法链:

string[] Words = new string[]
{"   KOOKABURRA", "Frogmouth", "kingfisher   ", "loon", "merganser"};

Words
        .Select(word => word.Trim())
        .Select(word => word.ToLower())
        .Where(word => word.StartsWith("k"))
        .OrderBy(word => word);

在 Visual Studio 项目中包含 Dump 扩展方法后,您可以像这样最低限度地检测它...

Words
    .Select(word => word.Trim())
    .Dump()
    .Select(word => word.ToLower())
    .Dump()
    .Where(word => word.StartsWith("k"))
    .Dump()
    .OrderBy(word => word)
    .Dump();

...或者更精细的像这样...

Words
    .Dump(w => "ORIGINAL: " + w, ConsoleColor.Yellow)
    .Select(word => word.Trim())
    .Dump(w => "TRIMMED: " + w, ConsoleColor.Yellow)
    .Select(word => word.ToLower())
    .Dump(w => "LOWERCASE: " + w, ConsoleColor.Green)
    .Where(word => word.StartsWith("k"))
    .Dump(w => "FILTERED to 'K': " + w, ConsoleColor.Red)
    .OrderBy(word => word)
    .Dump(w => "SORTED: " + w, ConsoleColor.Blue);

... 将输出分别呈现为图形的左侧或右侧:

作为预告片,我要说的是,虽然这确实有用,但您确实必须看到 LINQPad 可以使用相同的输出实现的增强可视化(为方便起见,再次为链接提供here)。

【讨论】:

    【解决方案2】:

    我的做法是在查询中插入断点,或者使用一个叫做 LINQPad 的工具。 http://www.linqpad.net/

    【讨论】:

      【解决方案3】:

      我相信您应该能够像在任何其他代码中一样放置断点。我不是 100% 确定,因为我经常将 LINQ 语法写成匹配的扩展方法。

      但是,这是另一种选择,您可以使用扩展方法重写查询并在每个方法上添加断点。

      如果有疑问,请使用 F11 :)

      另外,LINQPad 在这里应该可以提供一些帮助。

      【讨论】:

      • LINQPad 如何帮助我调试结果。如何在 linqpad 中设置断点。你能帮我指导一下吗?我可以下载 linqpad 的免费版本。请在此处发布一张图片,它可以帮助我在所有步骤中详细可视化调试 linq 查询。例如,假设什么存储在 let a 或 let w 中。什么是作为 c amd i a.sr.Title.Select((c, i) 的值传递的。如何以这种方式调试。寻求帮助。谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多