Sunday, May 06, 2007

LINQ,延迟的查询赋值(Deferred Query Evaluation)

3.3         延迟的查询赋值(Deferred Query Evaluation


机敏的读者(Observant readers)可能注意到标准的 Where 操作符在 C# 2.0 介绍里是用 yield 构造(construct)实现的。这是所有的标准操作符返回(return)有序列的数据(sequences of values)所采用的共同的实现技术。yield 关键词的用途有个很有趣的好处,就是查询实际是直到迭代结束(iterated over)后才被赋值的,即使是 foreach 语句或者手工使用下面(underlying)的 GetEnumerator MoveNext 方法也是如此。这种延迟的赋值方式允许查询像基于 IEnumerable<T> 值(IEnumerable<T>-based values)一样保留着,在每次 yield 方式返回可能不同的结果(yielding potentially different results)的时候可以被赋值多次(evaluated multiple times)。


 


对许多应用程序来说,这是期望(desired)得到的准确的行为(is exactly the behavior)。对应用程序想缓存查询赋值的结果,ToList ToArray 这两个操作符提供用来强制查询的直接赋值(force the immediate evaluation),以返回一个含有查询赋值的结果的 List<T> 或者Array 数组。


 


为了解延迟查询赋值是怎么工作的,请考察下面一段简单地查询一个数组的程序:


 


// declare a variable containing some strings
string[] names = { "Allen""Arthur""Bennett" };

// declare a variable that represents a query
IEnumerable<string> ayes = names.Where(s => s[0== 'A');

// evaluate the query
foreach (string item in ayes) 
  Console.WriteLine(item);

// modify the original information source
names[0= "Bob";

// evaluate the query again, this time no "Allen"
foreach (string item in ayes) 
    Console.WriteLine(item);

 


查询在每次变量 ayes 迭代结束(iterated over)时赋值。为了显示需要对结果做一份缓存的copy,我们可以简单给这个查询附加上一个 ToList 一个 ToArray 操作符,如下所示:


 


// declare a variable containing some strings
string[] names = { "Allen""Arthur""Bennett" };

// declare a variable that represents the result
// of an immediate query evaluation
string[] ayes = names.Where(s => s[0== 'A').ToArray();

// iterate over the cached query results
foreach (string item in ayes) 
    Console.WriteLine(item);

// modifying the original source has no effect on ayes
names[0= "Bob";

// iterate over result again, which still contains "Allen"
foreach (string item in ayes)
    Console.WriteLine(item);

 


ToList ToArray 都强制查询的赋值,就像执行一个标准查询操作符(如 First, ElementAt, Sum, Average, All, 等)返回一个单独的值(singleton values)一样。


 



待续, 错误难免,请批评指正,译者Naven 2005-10-22


No comments: