在调试时检查IEnumerable“堆栈”?

时间:2013-08-26 17:36:24

标签: c# linq visual-studio ienumerable

假设我们有一个源IEnumerable序列:

IEnumerable<Tuple<int, int>> source = new [] {
    new Tuple<int, int>(1, 2),
    new Tuple<int, int>(2, 3),
    new Tuple<int, int>(3, 2),
    new Tuple<int, int>(5, 2),
    new Tuple<int, int>(2, 0),
};

我们想要应用一些过滤器和一些转换:

IEnumerable<int> result1 = source.Where(t => (t.Item1 + t.Item2) % 2 == 0)
                                 .Select(t => t.Item2)
                                 .Select(i => 1 / i);
IEnumerable<int> result2 = from t in source
                           where (t.Item1 + t.Item2) % 2 == 0
                           let i = t.Item2
                           select 1 / i;

这两个查询是等价的,两者都会在最后一项上抛出DivideByZeroException

但是,当枚举第二个查询时,VS调试器将让我检查整个查询,因此非常方便地确定问题的根源。

VS Debugger is useful

但是,枚举第一个查询时没有等效的帮助。检查LINQ实现不会产生有用的数据,可能是由于二进制文件已经优化:

LINQ is too optimized

有没有办法有效地检查&#34;堆栈中的可枚举值&#34;不使用查询语法的IEnumerable s?查询语法不是一个选项,因为它不可能共享代码(即,转换是非常重要的并且不止一次使用)。

1 个答案:

答案 0 :(得分:1)

但你可以调试第一个。只需在任何一个lambdas上插入一个断点,你就可以自由地检查参数值或其他任何范围。

  

enter image description here

调试时,您可以检查(在第一个Wheret t.Item1t等内的情况下的值

  

enter image description here

至于您在第二个查询中执行最终select而不是第一个查询时可以检查IEnumerable<int> result1 = source.Where(t => (t.Item1 + t.Item2) % 2 == 0) .Select(t => new { t, i = t.Item2, }) .Select(result => 1 / result.i); 的原因,原因是您没有创建等效查询。您编写的第二个查询,当编译器写出时,将生成类似您的第一个查询。它会巧妙地创造出一些东西,但仍然显着不同。它会创建这样的东西:

let

let调用不只是选择该值,因为您编写的第一个查询会执行此操作。它选择一个新的匿名类型,从t子句和前一个值中提取值,然后修改后续查询以提取适当的变量。这就是为什么“先前”变量(即select仍然在查询结束时的范围内(在编译时和运行时;仅此一点应该是你的一个大提示)。使用上面提供的查询,当打破result.t时,您可以通过调试器看到{{1}}的值。