问题引出数组
这视乎是个彻底没必要要进行讨论的话题,由于linq(这里具体是linq to objects)原本就是针对集合类型的,数组类型做为集合类型的一种固然可使用了。不过我仍是想写一下,这个问题源于qq群里一位朋友的提问:.net的数组类型都隐式继承了Array类,该类是一个抽象类,而且实现了IEnumerable、ICollection、IList接口。但linq的方法都是针对实现了IEnumerable<T>泛型接口的,Array类并无实现这些泛型接口,为何可使用这些方法呢?布局
linq to objects的本质是经过扩展方法来实现集合的查询,这些扩展方法定义在一个Enumerable的静态类中。Enumerable类下的全部扩展方法的第一个参数都是IEnumerable<T> 类型,表示它能够经过IEnumerable<T>类型进行调用。spa
浅析数组类型.net
1. 全部数组类型都隐式派生自Array对象
当咱们定义一个FileStream[] 数组时,CLR会为当前的AppDomain建立一个FileStream[] 类型,该类型派生自 Array。因此数组是引用类型,在堆中分配内存空间。Array类是一个抽象类,定义了许多关于经常使用的实例方法和静态方法,供全部的数组类型使用。例如常见的:Length属性,CopyTo方法等等。blog
2. 全部的数组类型都隐式实现了IEnumerable<T>接口继承
就如上面所所的,这是一个理所固然的问题,为了提升开发效率,数组类型理应可使用linq进行查询。但因为数组能够是多维数组或者非0基数组,因此Array类并无实现IEnumerable<T>、ICollection<T>、IList<T> 这几个泛型接口,而只是实现了非泛型版本的。实际上,CLR会自动为一维的数组类型实现这些泛型接口(指定T类型参数的具体类型),而且还会为它们的父类实现。例如咱们定义一个FileStream[] 数组类型,那么CLR会为咱们建立以下的层次类型结构:接口
因为CLR的隐式实现,才使咱们能够将一维数组类型应用在须要IEnumerable<T>泛型接口的地方。内存
按照上面的说法,咱们能够将FileStream[] 类型的对象传递给以下的方法:开发
void F1(IEnumerable<object> oEnumerable);
void F2(ICollection<Stream> sCollection);
void F3(IList<FileStream> fList);
这是对于引用类型而言的,若是是值类型,则不为会它的基类实现这些接口。例如DateTimel类型(基类包括ValueType和Object),DateTime[]数组类型不能传递给上面的F1方法,这是由于值类型的数组的内存布局与引用类型的数组不一样。