teLine($"{Padding} About to yield {i}");
yield return i;
WriteLine($"{Padding} After yield");
}
WriteLine($"{Padding} Yielding final value");
yield return -1;
WriteLine($"{Padding} End of CreateEnumerable");
}
}
此处可以留意“After yield”是什么时候出现的,就会发现[1]:
l 在第一次调用MoveNext之前,CreateEnumerable中的代码不会被调用;
l 当调用MoveNext时,Current也同时变化;
l 在yield return的位置,代码就停止执行,在下一次调用MoveNext时又继续执行(再return一次)
yield的故事还没有完,此处就简短介绍。
yield return提供了逐个返回的条件,对于仅是取集合当中符合筛选条件的一项,用yield是方便的,逐个返回的情况下,不会占用过多的存储空间。但如果涉及到排序(或者比大小、最值)的问题,那必然要求集合当中的所有数据处于可用状态,这里也出现了一些传值的概念。
yield return属于延迟执行(Deferred Execution),延迟执行再区分为惰性求值(Lazy eva luation)和热情求值(Eager eva luation)。
Deferred but eager execution |
Deferred and lazy execution |
IEnumerable<int> GetComputation(int maxIndex) { var result = new int[maxIndex]; for(int i = 0; i < maxIndex; i++) { result[i] = Computation(i); } foreach(var value in result) { yield return value; } } |
IEnumerable<int> GetComputation(int maxIndex) { for(int i = 0; i < maxIndex; i++) { yield return Computation(i); } } |
详见:https://stackoverflow.com/questions/2515796/deferred-execution-and-eager-eva luation
下面这个例子,是惰性求值,迭代器返回的值受lambda表达式控制,并且是在每一次访问到这一个“点”的时候,再去返回 “点”的处理结果。热情求值是直接返回“点”,没有再过处理。两相比较,还得看具体的编程情况以作选择,此处不赘述。
static void Main(string[] args)
{
var sequence = Generate(10, () => DateTime.Now);
foreach (var value in sequence)
WriteLine($"{value:T}");
}
static IEnumerable<TResult> Generate<TResult>(int number, Func<TResult> generator)
{
for (var i = 0; i < number; i++)
{
Sleep(400);
yield return generator();
}
}
(为了逻辑上的全面性,)与延迟执行相对的是立即执行(Immediately Execution),是一次返回就完成函数的操作。
二、迭代器 IQueryable
LINQ to Object 是针对本地数据存储(local data store)来执行查询的,系统会根据lambda表达式里面的逻辑创建匿名的委托,并执行代码;
LINQ to SQL 针对的是在数据库执行的,会把查询条件解析成T-SQL,并且把SQL语句发送给数据库引擎。
关于,自动生成SQL语句这一点,可以做个尝试,例如:创建了一个EF,调试监控连接数据库后返回的变量类型。
var dbcontext = new CM_FORTESTEntities();
var tb1 = dbcontext.tblEmployees;
var tb2 = dbcontext.tblEmployees.Where(a => a.Id == 1);
var tb3 = dbcontext.tblEmployees.Where(a => a.Gender == "Male").OrderByDescending(a => a.Id);
咋一看,怎么还能是不同类型?但是再看类成员,会发现一些端倪:
public abstract class DbSet : DbQuery, IInternalSetAdapter
public abstract class DbQuery : IOrderedQueryable, IQueryable, IEnumerable, IListSource, IInternalQueryAdapter
public interface IOrderedQueryable : IQueryable, IEnumerable
好了,终于引入到这个朋友——IQueryable,IQueryable有些什么必要实现的方法呢?
public class QueryableSample : IQueryable
{
public Expression Expression => throw new NotImplementedException();
public Type ElementType =