据我所知,接口是实现者必须遵守的契约。但在这种情况下:
IEnumerable<int> numQuery = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
IEnumerable被用作集合类型,不是吗?为什么不做这样的事?
public class EnumCollection<T> : IEnumerable<T>
{
}
EnumCollection<T> numQuery = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
我想我错过了什么。。。
IEnumerable<T>
是一个表示序列的接口。现在集合通常可以用作序列(因此…List<T>
实现IEnumerable<T>
(,但反过来不一定成立。事实上,并不严格要求您甚至可以多次迭代序列(IEnumerable<T>
(。
许多LINQ操作检查您正在使用的序列是否也是集合(IList<T>
等(,以便提供优化的实现(.Count
而不是通过迭代计数等(。
.Where(...)
等的结果只是:一个序列。它不会因为从EnumCollection<T>
开始就被抛出到EnumCollection<T>
。在.Where
的情况下,数据甚至不存储在任何地方——它是一个在枚举时应用条件的过滤器。意思是:当你试图获取下一个项目时,它只是迭代内部序列,丢弃不匹配的项目。在OrderBy
的情况下,是缓冲的(根据需要-在一般情况下,不可能在没有缓冲的情况下进行排序(,但是:这是一个您通常不会接触到的实现细节。
IEnumerable
绝对是一个接口。
CCD_ 13和CCD_ 14是System提供的扩展方法。对接口执行操作的Linq。每个集合类实现IEnumerable<T>
接口背后的思想是,您希望一个使用集合的类只依赖于它真正需要的特定方法。
您不希望它们访问完整类上的其他方法的原因是,您可能希望在不更改使用它的类的情况下更改正在使用的底层实现。
例如,如果您希望在其他类中使用EnumCollection,那么您将显式地绑定到该实现。然而,如果您在using类中使用接口,则可以将EnumCollection的实现交换为StringCollection,并且您的类仍然可以工作,因为它们只需要IEnumerable接口。
这源于SOLID中的I。https://en.wikipedia.org/wiki/SOLID和https://en.wikipedia.org/wiki/Interface_segregation_principle
请注意List类有许多many接口;
[Serializable]
public class List<T> : System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.IList
并且HashSet类共享其中的一些。。。
[Serializable]
public class HashSet<T> : System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.ISet<T>, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable
来自https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netframework-4.7.2