关于c#:IQueryable,ICollection,IList&

Difference between IQueryable, ICollection, IList & IDictionary interface

我试图理解iQuery、iCollection、iList和iDictionary接口之间的区别这对于迭代、索引、查询等基本操作来说更快。

像collection、list、dictionary等哪个类最好用这些接口来初始化,我们什么时候应该使用这些类。使用这些类相对于其他类的基本优势。

我试着阅读其他有类似问题的帖子,但没有人回答我全部的问题。谢谢你的帮助。


所有这些接口都继承自IEnumerable,您应该确保理解它。该接口基本上允许您使用foreach语句中的类(在C中)。

  • ICollection是您列出的最基本的接口。它是一个可枚举的接口,支持一个计数。
  • iList是iCollection的一切,但它还支持添加和删除项、按索引检索项等。它是"对象列表"最常用的接口,我知道这很模糊。
  • iQueryable是一个支持Linq的可枚举接口。您总是可以从IList创建一个IQueryable,并使用Linq to对象,但您也发现IQueryable用于延迟执行Linq to SQL和Linq to实体中的SQL语句。
  • IDictionary是一种不同的动物,从某种意义上说,它是一种独特的值键映射。它也可枚举,因为您可以枚举键/值对,但除此之外,它的用途与您列出的其他用途不同。

每一个文档的msdn文档都是很好的,所以我将从那里开始完善您的理解。


我注意到@gunny229上面的答案中有几个问题,这就是我写这篇文章的原因。我在他的评论区也提到了这些问题。要更正那个帖子,我几乎要重写整个帖子,所以我想创建自己的。我不打算完全回答OP的问题,但我想指出在使用linq-to-sql时iqueryable和ienumerable之间的区别。

我在数据库(DDL脚本)中创建了以下结构:

1
CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

下面是记录插入脚本(DML脚本):

1
2
3
4
5
6
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

现在我的目标是简单地从数据库中的Employee表中获取前2条记录。因此,我在控制台应用程序中添加了一个ADO.NET实体数据模型项,指向数据库中的Employee表,并开始编写LINQ查询。

可查询路由代码:

1
2
3
4
5
6
7
8
9
10
using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

当我开始运行此程序时,我还在我的SQL Server实例上启动了一个SQL查询探查器会话,下面是执行摘要:

  • 激发的查询总数:1
  • 查询文本:SELECT TOP (2) .[Salary] AS [Salary] FROM [dbo].[Employee] AS
  • 只是IQueryable足够聪明,可以在数据库服务器端本身应用Top (2)子句,所以它在5条记录中只带2条。客户端计算机完全不需要进一步的内存过滤。

    IEnumerable路由的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    using (var efContext = new EfTestEntities())
    {
        IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
        employees = employees.Take(2);

        foreach (var item in employees)
        {
            Console.WriteLine(item);
        }
    }

    本案执行摘要:

  • 激发的查询总数:1
  • SQL事件探查器中捕获的查询文本:SELECT [Extent1].[Salary] AS [Salary]
    FROM [dbo].[Employee] AS [Extent1]
  • 现在的问题是,IEnumerableSalary表中的所有5条记录都带来,然后在客户机上执行内存过滤以获得前2条记录。因此,更多的数据(本例中还有3条记录)不必要地通过线路传输。


    IQueryable、IList、IDictionary、ICollection继承IEnumerable接口。类型集合的所有接口都将继承IEnumerable接口。

    IEnumerable和IQueryable之间的差异IEnumerable:-运行返回IEnumerable类型的查询时。IEnumerable将首先执行第一个查询,然后执行为该查询编写的子查询。

    示例:-如果要从特定国家获取前10个人口记录,则我们将在LINQ中使用的查询是

    ienumerable ou population=从印度的s中选择s.population;//第一个查询_ population=u population.take(10);//第二个查询

    现在,如果我们执行这个查询,首先将执行查询,IEnumerable将从SQL Server获取所有填充的记录,然后将数据存储在进程内存中,然后在下一个查询中执行前10个填充(在SQL Server上执行两次)。

    如果我们使用iqueryable执行相同的查询。

    iqueryable_population=从印度的s中选择s.population;//第一个查询_ population=u population.take(10);//第二个查询

    在这个iQueryable中,它将同时执行两个查询,从这个意义上说,它将在一个查询中获得前10位的填充,而不是再次获取数据和筛选前10位(在SQL Server上执行一次)。

    IQueryable和IEnumerable的结论

  • 如果要针对数据库中的数据编写查询,则使用可查询的。
  • 如果您正在查询进程内数据,那么使用IEnumerable。IEnumerable具有getEnumerator()、current()和moveNext()方法。