是否延迟执行

本文关键字:执行 延迟 是否 | 更新日期: 2023-09-27 18:04:10

下面关于延迟执行的评论是否正确?

1. var x = dc.myTables.Select(r=>r);//yes
2. var x = dc.myTables.Where(..).Select(r=>new {..});//yes
3. var x = dc.myTables.Where(..).Select(r=>new MyCustomClass {..});//no

换句话说,我一直认为投射自定义类对象总是会导致紧急执行。但我找不到支持或否认它的参考文献(尽管我看到的结果与之矛盾,因此这篇文章)

是否延迟执行

问题中的每个语句都是延迟执行的例子。SelectWhere语句的内容对结果值是否延迟执行没有影响。Select + Where表述本身说明了这一点。

作为反例考虑Sum方法。不管输入是什么,它总是急切地执行。

var sum = dc.myTables.Sum(...);  // Always eager 

为了证明您的观点,您的测试应该是这样的:

var tracer = string.Empty;
Func<inType, outType> map = r => {
       tracer = "set";
       return new outType(...);
    } 
var x = dc.myTables.Where(..).Select(map);
// this confirms x was never enumerated as tracer would be "set".
Assert.AreEqual(string.Empty, tracer);
// confirm that it would have enumerated if it could
CollectionAssert.IsNotEmpty(x);

根据我的观察,强制立即执行的唯一方法是强制对集合进行迭代。我通过在LINQ上调用.ToArray()来做到这一点。

通常返回序列的方法使用延迟执行:

IEnumerable<X> ---> Select ---> IEnumerable<Y>

和返回单个对象的方法不会:

IEnumerable<X> ---> First ---> Y

所以,像Where, Select, Take, Skip, GroupByOrderBy这样的方法使用延迟执行是因为它们可以,而像First, Single, ToListToArray这样的方法不使用延迟执行是因为它们不能。

从这里

.Select(...)总是被延迟。

当你使用IQueryable<T>时,这个和其他延迟执行方法建立一个表达式树,直到它被迭代才编译成一个实际的可执行表达式。也就是说,您需要:

  • 对预计的可枚举对象执行for-each。
  • 调用一个在内部枚举可枚举的方法(即:.Any(...), .Count(...), .ToList(...),…).