• 数组为什么可以使用linq查询


    问题引出

      这视乎是个完全不必要进行讨论的话题,因为linq(这里具体是linq to objects)本来就是针对集合类型的,数组类型作为集合类型的一种当然可以使用了。不过我还是想写一下,这个问题源于qq群里一位朋友的提问:.net的数组类型都隐式继承了Array类,该类是一个抽象类,并且实现了IEnumerable、ICollection、IList接口。但linq的方法都是针对实现了IEnumerable<T>泛型接口的,Array类并没有实现这些泛型接口,为什么可以使用这些方法呢?

      linq to objects的本质是通过扩展方法来实现集合的查询,这些扩展方法定义在一个Enumerable的静态类中。Enumerable类下的所有扩展方法的第一个参数都是IEnumerable<T> 类型,表示它可以通过IEnumerable<T>类型进行调用。

    浅析数组类型

    1. 所有数组类型都隐式派生自Array

      当我们定义一个FileStream[] 数组时,CLR会为当前的AppDomain创建一个FileStream[] 类型,该类型派生自 Array。所以数组是引用类型,在堆中分配内存空间。Array类是一个抽象类,定义了许多关于常用的实例方法和静态方法,供所有的数组类型使用。例如常见的:Length属性,CopyTo方法等等。

    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方法,这是因为值类型的数组的内存布局与引用类型的数组不同。

  • 相关阅读:
    Express 框架中 使用ejs
    Nodejs操作MongoDB数据库
    MongoDB基础操作
    node中的包、npm和模块
    background
    animation
    transition
    transform
    【SpringCloud】各种组件的更新情况
    【SpringCloud】版本选择
  • 原文地址:https://www.cnblogs.com/4littleProgrammer/p/4949224.html
Copyright © 2020-2023  润新知