C# 什么';IEnumerable和Array、IList和List之间的区别是什么?

C# 什么';IEnumerable和Array、IList和List之间的区别是什么?,c#,C#,IEnumerable和Array之间有什么区别 IList和List之间有什么区别 它们似乎具有相同的功能。IEnumerable和IList是。数组和列表是类。数组实现IEnumerable。列表实现了扩展IEnumerable的IList 编辑:正如itowlson在一篇评论中提到的,数组还实现了IList。IEnumerable是一个接口,允许通过项目集合进行迭代(例如,通过foreach关键字) 数组是.NET固有的。它保存相同类型的项目,但大小固定。一旦创建了包含x个元素的数组,它就

IEnumerable
Array
之间有什么区别

IList
List
之间有什么区别

它们似乎具有相同的功能。

IEnumerable和IList是。数组和列表是类。数组实现IEnumerable。列表实现了扩展IEnumerable的IList


编辑:正如itowlson在一篇评论中提到的,数组还实现了IList。

IEnumerable是一个接口,允许通过项目集合进行迭代(例如,通过foreach关键字)

数组是.NET固有的。它保存相同类型的项目,但大小固定。一旦创建了包含x个元素的数组,它就无法增长或收缩

IList定义了列表的接口,还实现了IEnumerable

列表实现了IList接口;它是一种具体的列表类型

NET列表和数组之间的区别在于列表可以添加元素——它们的大小足以容纳所有必需的项。该列表将其内部存储在一个数组中,当该数组不再大到足以容纳所有元素时,将创建一个新数组,并跨该数组复制项


IList和数组都实现IEnumerable。接口就是这样工作的——类实现了契约并以类似的方式运行,因此可以被类似地对待(您知道类实现了IEnumerable,您不需要知道如何或为什么)。我建议您仔细阅读接口等方面的内容。

IEnumerable只提供最低限度的“iterable”功能。您可以遍历序列,但仅此而已。这有缺点——例如,使用IEnumerable计算元素或获取第n个元素的效率非常低——但它也有优点——例如,IEnumerable可以是一个无止境的序列,就像素数序列一样

数组是一个具有随机访问的固定大小集合(即,您可以对其进行索引)

列表是一个具有随机访问权限的可变大小集合(即,您可以添加和删除元素)


IList是一个接口,它将列表功能(计数、添加、删除、索引器访问)从各种具体类(如list、BindingList、ObservableCollection等)中抽象出来。

IEnumerable
是一个通用接口,被许多类使用,例如
数组
列表
字符串
,以便有人在集合上迭代。基本上,它是驱动
foreach
语句的因素


IList
通常是向最终用户公开
List
类型变量的方式。此接口允许对基础集合进行随机访问。

生成IEnumerable集合是惰性的。 例如:

public IEnumerable GetTwoInts()
{
收益率1;
收益率2;
}
公之于众
{
var twoInts=GetTwoInts();
}

在方法中,对GetTwoInts()的调用实际上不会导致执行方法GetTwoInts,因为枚举从未被迭代过。

这是一篇老文章,但仍然考虑回复。 IEnumerable是一种行为,而Array是一种数据结构(具有固定大小的元素的连续集合,便于通过索引访问元素)。
当数组实现IEnumerable时,它还应该描述IEnumerable的固有属性(促进对集合的迭代)。

为了补充其他答案,请注意,在执行foreach语句时,
IList
List
之间存在性能差异

这是因为
List.GetEnumerator
返回的迭代器对象是值类型,而
IList.GetEnumerator
返回的迭代器对象是引用类型,因此需要内存分配(请参阅)


在我看来,
IList
无论如何都不是一个很好的界面。例如,调用
Add
可以抛出(请参阅)。如果您需要封装,最好使用
IEnumerable
IReadOnlyList

除了其他答案之外,了解使用LINQ时可枚举与列表/数组之间的差异会对性能产生巨大影响。简而言之,Enumerable可以被视为查询生成器,而List/Array是查询的结果

在使用EntityFramework的LINQ to SQL上下文中,前者只是构建SQL查询,而没有对数据库执行查询,也没有将任何数据加载到内存中,而后者正好相反。这就是为什么我们会推迟调用
.ToList()
,直到我们需要它在内存中执行业务逻辑

在其他上下文中,返回IEnumerable的LINQ表达式将推迟执行,直到调用
.ToList()
。考虑下面的例子:

void Main()
{
    var w1 = "AB".AsEnumerable();
    Console.WriteLine($"W1: 1");
    w1 = w1.Where(W1);
    Console.WriteLine($"W1: 2");
    w1 = w1.Where(W2);
    Console.WriteLine($"W1: 3");
    w1.ToList();    
    Console.WriteLine($"----------");

    var w2 = "CD".AsEnumerable();
    Console.WriteLine($"W2: 1");
    w2 = w2.Where(W1);
    Console.WriteLine($"W2: 2");
    w2 = w2.ToList();
    Console.WriteLine($"W2: 3");
    w2 = w2.Where(W2);
    Console.WriteLine($"W2: 4");
    w2.ToList();    
    Console.WriteLine($"----------");
}

bool W1(char arg)
{
    Console.WriteLine($"W1:{arg}");
    return true;
}

bool W2(char arg)
{
    Console.WriteLine($"W2:{arg}");
    return true;
}

OUTPUT:
W1: 1
W1: 2
W1: 3
W1:A
W2:A
W1:B
W2:B
----------
W2: 1
W2: 2
W1:C
W1:D
W2: 3
W2: 4
W2:C
W2:D
----------
在第一个示例中,两个
.Where()
被“追加”并在调用
.ToList()
时一起执行,其中项“A”首先通过管道,然后项“B”,因此在输出中看到“AABB”,而在第二个示例中,
.Where()如果我们随后立即调用
.ToList()
,则每次都会执行
,因此会看到“CD”,然后再次看到“CD”,并输出两次。因此,每次将可枚举项转换为列表或数组时,都会对集合中的所有项进行一次迭代,这在集合较大时会对性能产生影响

虽然我们不倾向于以这种方式编写代码,在LINQ调用之间调用
.ToList()
,但当我们将代码分解为返回
List/Array
而不是
IEnumerable
的可重用方法时,这种情况会发生得更频繁

然而,这并不意味着我们应该总是对
IEnumerable
进行操作。作为m
void Main()
{
    var w1 = "AB".AsEnumerable();
    Console.WriteLine($"W1: 1");
    w1 = w1.Where(W1);
    Console.WriteLine($"W1: 2");
    w1 = w1.Where(W2);
    Console.WriteLine($"W1: 3");
    w1.ToList();    
    Console.WriteLine($"----------");

    var w2 = "CD".AsEnumerable();
    Console.WriteLine($"W2: 1");
    w2 = w2.Where(W1);
    Console.WriteLine($"W2: 2");
    w2 = w2.ToList();
    Console.WriteLine($"W2: 3");
    w2 = w2.Where(W2);
    Console.WriteLine($"W2: 4");
    w2.ToList();    
    Console.WriteLine($"----------");
}

bool W1(char arg)
{
    Console.WriteLine($"W1:{arg}");
    return true;
}

bool W2(char arg)
{
    Console.WriteLine($"W2:{arg}");
    return true;
}

OUTPUT:
W1: 1
W1: 2
W1: 3
W1:A
W2:A
W1:B
W2:B
----------
W2: 1
W2: 2
W1:C
W1:D
W2: 3
W2: 4
W2:C
W2:D
----------