一、关于集合遍历的模式,本人目前所知的有两种,一种是length-index模式,一种是interator模式,前一种在应用在数组中,另一种则在泛型集合中广为应用,这也是IEnumerator<T>的设定模式,为了在同时遍历一个集合(多线程,内嵌遍历)的情况下,能正确获取当前值,因此泛型集合继承的接口为IEnumerable<T>,其规范是返回 GetEnumerator(),这样在同时遍历一个集合时,获得的是不同的IEnumertor<T>对象,这样就相当于在同时查阅一本书,但可以按照不同的书签(IEnumerator)来查。
疑问:(1)除了这两种模式是否还有其他的模式,其相通之处?
(2)对于数组而言,因其length-index模式,其foreach语法下和for循环下,编译器生成的CIL代码一致,所以其效率也应当一致?
(3)还有那个基于Duck—Typing的法则,对于foreach的支持,不一定非得继承IEnumerable<T>,也可以实现MoveNext() Current()即可;
(4)对于Stack<T> ,Queue<T>,dictionary<Tkey,TElement>中,无法进行索引访问的,怎么MoveNext() ,怎么获取Current值?如果内部采取List等含索引访问的对象,那最终不还是Length-index模式?
二、关于集合中IEnumerable<T>的扩展,正是因为有了泛型,有了接口扩展,才会有这么强大的linq语法支持,(Ps:接口扩展,基于对已声明的类,可以再类外再自定义该类的实例方法 语法(eg.):void FunctionMethod(this Class1 c1,object object1); 其中Class1 即指需要进行扩展的类,甚至可以是接口,而对于接口的扩展方法,其所有继承该接口的子类均可以使用,,,本人觉得这个真的是修改和升级的强大工具啊,,,木有它,就木有linq)。
其中关于linq语法中,有一个相当重要而易忽略的特性,即推迟执行,,:所谓推迟执行,即指在System.linq.Enumerable类中各种查询函数里面所传递的委托实例,即lambada表达式,lambada表达式,并不会在调用该查询函数时执行,而是只有在遍历是才会执行,如:Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>),其中Func<TSource, TResult>的实例,并不会在调用Select函数时执行, 而是在遍历TSource时,才执行,而且会在每次遍历时执行,稍不注意就极大地影响性能;
示例代码如下:
using System.Collections;
using System.Linq;
using System;
class Program
{
static void Main()
{
var employees=new[]
{
new {Name="liSan",Age="30"},
new {Name="WangSi",Age="41"}
};
var items=employees.Select(employee=>{
Console.WriteLine("TestMark1");
return employee.ToString();}
);
Console.WriteLine("TestMark2");
foreach(var item in items)
{
Console.WriteLine(item);
}
Console.WriteLine(items.Count());
}
}
//Output:
TestMark2
TestMark1
{Name=liSan,Age=30}
TestMark1
{Name=WangSi,Age=41}
TestMark1
TestMark1
2
以上结果均经过网上编译器编译实现;http://www.compileonline.com/compile_csharp_online.php
为解决每次遍历都会重新执行查询表达式,因此一般是给个缓存,如 var items=items.ToArray();即在下次执行对items的遍历时,查询条件不会再次执行;
疑问:
(5)推迟执行的内部实现是怎么回事,,,?按说Select函数会有对Func(Parameter1)的调用,那么怎么会延迟了?