先说点理论 1.OfType : 即接受基于IEnumerable<T> 接口的信息源,也接受那些在 .NET Framework 1.0 中出现的非参数化的 IEnumerable 接口(non-parameterized IEnumerable interface)。OfType 操作符允许用户在标准的 .NET collections 类(classic .NET collections)上应用标准查询操作符,就像下面的程序: 代码: IEnumerable classic =new OlderCollectionType(); IEnumerable<object> modern = classic.OfType<object>(); 在这个例子中,变量 modern 产生了与变量 classic 一样的顺序的数据列表(same sequence of values),但是不同的是它的类型兼容最新的 IEnumerable<T> 代码(modern IEnumerable<T> code),包括标准查询操作符。 OfType 操作符对新的信息源也是有用的,因为它允许从基于类型的信息源(source based on type)中过滤出数据(filtering values from)。当要制作新的顺序的时候(producing the new sequence),OfType 简单的忽略(omits)原有序列的成员(members of the original sequence)就可以了,这是与类型实参(type argument)不相符的。分析下面的程序,目标是将 string 字符串数据从一个有不同种类数据的数组(heterogeneous array)中分解出来: 代码: object[] vals ={ 1, "Hello", true, "World", 9.1 }; IEnumerable<string> justStrings = vals.OfType<string>(); 当在 foreach 语句中列举(enumerate)变量 justStrings 中的数据时,将得到两个依次为“Hello”和“World”的 string 字符串序列(a sequence of two strings )。 2.ToList,ToArray: 对应用程序想缓存查询赋值的结果,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)一样。
ToArray: publicvoid ToArray() { double[] doubles ={ 1.7, 2.3, 1.9, 4.1, 2.9 }; var sortedDoubles = from d in doubles orderby d descending select d; var doublesArray = sortedDoubles.ToArray(); Console.WriteLine("Every other double from highest to lowest:"); for (int d =0; d < doublesArray.Length; d +=2) { Console.WriteLine(doublesArray[d]); } }
ToList: publicvoid ToList() { string[] words ={ "cherry", "apple", "blueberry" }; var sortedWords = from w in words orderby w select w; var wordList = sortedWords.ToList(); Console.WriteLine("The sorted word list:"); foreach (var w in wordList) { Console.WriteLine(w); } }
OfType: publicvoid OfType() { object[] numbers ={ null, 1.0, "two", 3, 4.0f, 5, "six", 7.0 }; var doubles = numbers.OfType<double>(); Console.WriteLine("Numbers stored as doubles:"); foreach (var d in doubles) { Console.WriteLine(d); } }
ToArray:Result Every other double from highest to lowest: 4.1 2.3 1.7 ToList:Result The sorted word list: apple blueberry cherry ToDictionary:Result Bob's score: {Name=Bob, Score=40} OfType:Result Numbers stored as doubles: 1 7