假设我们有一个源 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 调试器会让我检查整个查询,从而非常方便地确定问题的根源。
但是,在枚举第一个查询时没有等效的帮助。检查 LINQ 实现没有产生有用的数据,可能是因为二进制文件被优化了:
在不使用查询语法时,有没有一种方法可以有效地检查 IEnumerable
的“堆栈”中的可枚举值?查询语法不是一个选项,因为使用它共享代码是不可能的(即,转换非常重要并且使用了不止一次)。
最佳答案
但是您可以调试第一个。只需在任何一个 lambda 上插入一个断点,您就可以自由检查参数的值或范围内的任何其他内容。
调试时,您可以检查(在第一个 Where
内中断的情况下)t
、t.Item1
、等等
至于在第二个查询中执行最后的 select
时可以检查 t
而不是第一个查询的原因,这是因为您没有创建等效查询.您编写的第二个查询在由编译器写出时,不会生成类似于您的第一个查询的内容。它将创造一些微妙但仍然显着不同的东西。它会创建这样的东西:
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
的值。
关于c# - 调试时检查 IEnumerable "stack"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18449745/