Qual é a diferença entre IEnumerable e Array, IList e List?


91

Qual é a diferença entre IEnumerablee Array?

Qual é a diferença entre IListe List?

Eles parecem ter a mesma função.

Respostas:


101

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.


2
De acordo com a resposta aceita aqui stackoverflow.com/questions/1826658/… . Count on IEnumerable é quase o mesmo porque tenta chamar Count on ICollection
Karsten,

15
Sim e não. O método de extensão Count () verifica se o IEnumerable também é um ICollection e chama sua propriedade Count se for. Se o IEnumerable não for um ICollection, Count () volta a iterar a sequência. Talvez eu devesse ter dito "é muito ineficiente contar elementos usando apenas IEnumerable", porque é claro que a presença de IEnumerable não impede você de usar um método mais eficiente se o objeto tiver um, e os métodos de extensão LINQ to Objects fazem exatamente aquele.
itowlson

16

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.


1
Adicionando este comentário para leitores que não lêem todas as respostas: arrays e List <> implementam IList <> (arrays implementam muito dele explicitamente, provavelmente porque muitos dos membros lançam uma NotSupportedException). Também é mais correto dizer que IList herda de IEnumerable do que dizer que ele o implementa.
phoog de

9

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.


Nem eu fiz! O que acontece se você começar a chamar IList.RemoveAt em uma matriz?
Mark Simpson

Ele lança um NotSupportedException. (Observe IList.RemoveAt e métodos IList semelhantes são explicitamente implementados em Array para que não apareçam em uma referência de Array normal!)
itowlson

1
@itowlson Eu diria que apenas System.Array (uma classe em si) implementa IList, mas T [] não implementa IList <T>. T [] implementa IEnumerable <T> em vez disso. Acho que o OP não necessariamente pediu System.Array ao solicitar "Array" IMHO
usr-local-ΕΨΗΕΛΩΝ

6

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.


Você poderia elaborar um pouco? Não tenho certeza se entendi direito. Você pode mostrar uma linha de código posteriormente que realmente resultará na execução desse método? Obrigado!
paaone

@paaone fez twoIntsuma foreachchamada ou twoInts.ToList().
row1

2

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.


2

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> .


1

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.


0

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).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.