了解下 IEnumerable、ICollection、IList 和 IQueryable 接口

在数据集合中,经常会用 IEnumerable、ICollection、IList 和 IQueryable 这些类型来定义变量和属性,今天就来了解下这些接口的特征及适用的场景。

以便我们增强代码的强壮性及提高程序性能。

先看下这几个接口的之间的关系。

1、IEnumerable 接口

namespace System.Collections
{
    public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }
}

IEnumerable 是所有非泛型集合的基本接口。它只有一个 GetEnumerator() 方法,返回一个 IEnumerator 。IEnumerator 提供了 Current 属性、 MoveNext() 和 Reset() 方法来遍历集合的能力。也就是说,IEnumerator 提供了一个可以使用 foreach 语句遍历功能的容器。所以,如果要使用 foreach 遍历访问的对象需要实现 IEnumerable 或声明 GetEnumerator() 方法的类型。

IEnumerable<T> 是安全且通用的泛型集合的基本接口。

namespace System.Collections.Generic
{
    public interface IEnumerable<out T> : IEnumerable
    {
        new IEnumerator<T> GetEnumerator();
    }
}

为了与非泛型集合的方法保持兼容,IEnumerable<T>实现 IEnumerable。这允许将泛型集合传递给需要 IEnumerable 对象的方法。

IEnumerable<T> 相比 IEnumerable 带有更多的扩展方法,主要用于集合的过滤操作。而且,IEnumerable<T> 中的元素都是只读,类型集合的元素是不能修改。

另外,在 EFCore 中使用 linq 查询并返回 IEnumerable或者IEnumerable<T> 时,它是将所有匹配到的所有对象从数据库加载到内存中,而后有其它过滤、排序等都是基于内存操作。

比如:

IEnumerable<Person> query = _db.Person.Where(a => a.Name.StartsWith("苏"));
query = query.Take(2);

上面这两行代码中,在数据库执行 SQL 语句会返回所有符合 Where 条件的记录,然后将这些记录装载到内存中,然后再从中取出 2 条记录。

如果只是一个简单的(只读)集合,IEnumerable或者IEnumerable<T>是足够了。

2、ICollection

namespace System.Collections
{
    public interface ICollection : IEnumerable
    {
        int Count { get; }

        bool IsSynchronized { get; }

        object SyncRoot { get; }

        void CopyTo(Array array, int index);
    }
}

ICollection 扩展了 IEnumerable 接口,并且提供了一些属性。如:Count 返回集合中包含元素的数量,IsSynchronized 返回访问是否同步,即是否线程安全。

ICollection<T> 接口:

namespace System.Collections.Generic
{
    public interface ICollection<T> : IEnumerable<T>, IEnumerable
    {
        int Count { get; }

        bool IsReadOnly { get; }

        void Add(T item);

        bool Contains(T item);

        void CopyTo(T[] array, int arrayIndex);

        bool Remove(T item);
    }
}

通过上面的接口的定义,它定义了一组方法和属性,可以根据情况来选择是否可以满足需求。

ICollection<T> 与非泛型 ICollection 接口不同,ICollection<T> 接口增加了添加、删除和搜索项目这些常用的功能。

当我们出现以下情况时,可以考虑使用 ICollection<T> :

  • 统计集合元素数量

  • 需要编辑集合元素

  • 搜索集合

  • 使用 IEnumerable<T> 接口中 Where 扩展方法进行过滤操作

3、IList

namespace System.Collections
{
    public interface IList : ICollection, IEnumerable
    {
        bool IsFixedSize { get; }

        bool IsReadOnly { get; }

        object? this[int index] { get; set; }

        int Add(object? value);

        void Clear();

        bool Contains(object? value);

        int IndexOf(object? value);

        void Insert(int index, object? value);

        void Remove(object? value);

        void RemoveAt(int index);
    }
}

IList 是 ICollection 接口的后代,它的实现分为三类:

  1. Read-Only :只读,无法修改集合中的元素

  2. Fixed-Size :固定集合大小,不允许添加或删除元素,但允许修改现有元素

  3. 改变集合大小 :允许添加、删除和修改元素

除了 ICollection 提供的属性和方法之外 ,还提供了通过索引来访问的集合中的元素。例如:RemoveAt(int index) 及在两个元素间插入元素 Insert(int index,object? value) 等。IList 对应的泛型列表 IList<T> 接口定义如下:

namespace System.Collections.Generic
{
    public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
    {
        T this[int index] { get; set; }

        int IndexOf(T item);

        void Insert(int index, T item);

        void RemoveAt(int index);

    }
}

如果超出 ICollection<T> 接口中提供的功能,且有以下两点中的情形,那么就可以考虑使用 IList 或 IList<T> 接口。

  • 需要修改集合中的元素

  • 需要快速定位集合中的元素或排序

4、IQueryable

namespace System.Linq
{
    public interface IQueryable : IEnumerable
    {
        Type ElementType { get; }
        Expression Expression { get; }
        IQueryProvider Provider { get; }
    }
}

根据上面的接口代码,它存在于 System.Linq 命名空间中。IQueryable 是从 IEnumerable 继承的。IEnumerable 能操作的,IQueryable 也都可以操作。

IQueryable 将 Linq 表达式转换为在数据库执行的 Sql 语句;且支持自定义查询和延迟加载。

IQueryable<T> 接口如下 :

namespace System.Linq
{
    public interface IQueryable<out T> : IEnumerable<T>, IEnumerable, IQueryable
    {
    }
}

IQueryable 在某些情况下可以提高查询情况。例如:

IEnumerable<Person> query = _db.Person.Where(a => a.Name.StartsWith("苏"));
query = query.Take(2);


IQueryable<Person> query = _db.Person.Where(a=>a.Name.StartsWith("苏"));
query = query.Take(2);

两个查询看起来相同,但从性能的角度来看,IQueryable<T> 返回的是在数据库执行过滤的记录。这提高了查询和使用的内存的性能。它返回的过滤后且前2条记录,而不是全部。

如果要用 Linq 表达式来过滤,使用 IQueryable 是最佳方案。

最后,祝大家学习愉快!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值