Respostas:
IEnumerable fornece apenas funcionalidade "iterável" mínima. Você pode percorrer a sequência, mas isso é tudo. Isso tem desvantagens - por exemplo, é muito ineficiente contar elementos usando IEnumerable ou obter o enésimo elemento - mas também tem vantagens - por exemplo, um IEnumerable pode ser uma sequência infinita, como a sequência de primos.
Array é uma coleção de tamanho fixo com acesso aleatório (ou seja, você pode indexar nela).
Lista é uma coleção de tamanho variável (ou seja, você pode adicionar e remover elementos) com acesso aleatório.
IList é uma interface que abstrai a funcionalidade da lista (contar, adicionar, remover, acesso do indexador) longe das várias classes concretas, como List, BindingList, ObservableCollection, etc.
IEnumerable é uma interface que permite a iteração por meio de uma coleção de itens (por exemplo, por meio da palavra-chave foreach).
Uma matriz é um .NET intrínseco. Ele contém itens do mesmo tipo, mas é de tamanho fixo. Depois de criar uma matriz com x elementos, ela não pode aumentar ou diminuir.
IList define a interface para uma lista e também implementa IEnumerable.
List implementa a interface IList; é um tipo concreto de lista.
A diferença entre as listas .NET e os arrays é que as listas podem ter elementos adicionados a elas - elas crescem e ficam grandes o suficiente para conter todos os itens necessários. A lista armazena isso internamente em uma matriz e, quando a matriz não é mais grande o suficiente para conter todos os elementos, uma nova matriz é criada e os itens copiados.
IList e arrays implementam IEnumerable. É assim que as interfaces funcionam - as classes implementam o contrato e se comportam de maneira semelhante e podem ser tratadas da mesma forma como resultado (você sabe que a classe implementa IEnumerable, você não precisa saber os comos ou os porquês). Eu sugiro que você leia sobre interfaces e assim por diante.
IEnumerable e IList são interfaces . Array e List são classes. Array implementa IEnumerable. List implementa IList, que estende IEnumerable.
Edit: como itowlson mencionou em um comentário, Array também implementa IList.
A geração de uma coleção IEnumerable é lenta. Exemplo:
public IEnumerable<int> GetTwoInts()
{
yield return 1;
yield return 2;
}
public void Something()
{
var twoInts = GetTwoInts();
}
No método Something, a chamada para GetTwoInts () não resultará realmente na execução do método GetTwoInts, pois a enumeração nunca é iterada.
twoIntsuma foreachchamada ou twoInts.ToList().
IEnumerableé uma interface de uso geral que é usado por muitas classes, tais como Array, Liste String, a fim de deixar alguém iteração sobre uma coleção. Basicamente, é o que impulsiona a foreachdeclaração.
IListé normalmente como você expõe variáveis de tipo Listaos usuários finais. Essa interface permite acesso aleatório à coleção subjacente.
Para complementar as outras respostas, observe que há uma diferença de desempenho entre IList<T>e List<T>ao executar uma instrução foreach.
Isso List<T>.GetEnumeratorocorre porque o objeto iterador retornado por é um tipo de valor, enquanto o retornado por IList<T>.GetEnumeratoré um tipo de referência e, portanto, requer uma alocação de memória (consulte Enumerador do tipo de valor da lista em c # ).
Na minha opinião, IList<T>não é uma interface muito boa. Por exemplo, chamar Addpode lançar (consulte Por que array implementa IList? ). Se você precisar de encapsulamento, seria melhor usar IEnumerable<T>ouIReadOnlyList<T> .
Além de outras respostas, compreender a diferença entre Enumerable vs List / Array ao usar o LINQ pode ter um grande impacto no desempenho. Resumindo, Enumerable pode ser percebido como um construtor de consulta, enquanto List / Array é o resultado da consulta.
No contexto de LINQ to SQL usando EntityFramework, o primeiro é apenas construir a consulta SQL sem executá-la no banco de dados nem carregar nenhum dado na memória, enquanto o último é o oposto. É por isso que adiaríamos a chamada.ToList() até precisarmos dela na memória para realizar a lógica de negócios.
Em outro contexto, a expressão LINQ que retorna IEnumerable adiará a execução até que .ToList()seja chamada. Considere o exemplo abaixo:
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
----------
No primeiro exemplo, dois .Where()estão sendo "anexados" e executados juntos no final quando .ToList()é chamado com o item " A " passando pelo tubo primeiro e depois o item " B ", portanto, vendo " AABB " na saída, enquanto no segundo exemplo, O .Where()é executado toda vez se chamarmos .ToList()imediatamente depois, portanto, vendo " CD " e " CD " novamente, a saída é duas vezes. Portanto, toda vez que um Enumerable é convertido em uma lista ou um array vai custar um O (n) iteração sobre todos os itens da coleção, o que terá impacto no desempenho quando a coleção for grande.
Embora não tenhamos tendência de escrever código dessa maneira chamando .ToList()entre as chamadas do LINQ, isso aconteceria com mais frequência quando fatoramos o código em métodos reutilizáveis que retornam em List/Arrayvez de IEnumerable.
Isso, entretanto, não significa que devemos operar sempre IEnumerable. Conforme mencionado por towlson , essas operações, como .Count()causarão iteração sobre a coleção, enquanto uma Lista ou Matriz teria essas informações pré-calculadas e, portanto, a conversão para List/Arrayseria mais eficiente se você planeja chamar .Count()várias vezes. É também por isso que há uma .Countpropriedade em uma lista em vez de um .Count()método para contá-la.
Esta é uma postagem antiga, mas ainda pensei em responder. IEnumerable é um comportamento enquanto Array é uma estrutura de dados (coleção contígua de elementos com tamanho fixo, facilitando o acesso a elementos por índices). Quando um Array implementa IEnumerable, ele também deve representar a propriedade inerente de IEnumerable (para facilitar a iteração na coleção).