Converta livremente entre List <T> e IEnumerable <T>

103

Como posso converter a List<MyObject>em IEnumerable<MyObject>e depois voltar?

Quero fazer isso para executar uma série de instruções LINQ na Lista, por exemplo Sort()

TK.
fonte
Esta é a questão abordada nesta questão stackoverflow.com/questions/31708/…
John

Respostas:

148
List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myEnumerable.ToList();
Tamas Czinege
fonte
30
No entanto, observe que myEnumarable é a mesma instância de objeto que myList, mas listAgain não é a mesma instância de objeto que myEnumerable. Dependendo do que você deseja fazer e do que é myEnumerable, "List <string> listAgain = myEnumerable as List <string>;" pode ser melhor.
ChrisW
1
Chrisw: Ah, sim, você está certo, é claro, mas a interface de IEnumerable <T> é imutável, então não causará problemas nessa direção e o cast back apenas parece sujo quando você tem uma função que cuidará da segurança de tipos.
Tamas Czinege
1
Você também pode apenas usar o objeto myList original. (Eu acho que eu realmente não entendo a pergunta)
sth
6
É só que se ele editar minhaLista, ele estará editando meuEnumerável, mas se ele editar a listaAvem, ele não estará editando meuEnumerável.
ChrisW
15
Não se esqueça using System.Linq;ou você não conseguirá ToList ()
Jason
21

A List<T>é um IEnumerable<T>, então, na verdade, não há necessidade de 'converter' a List<T>em um IEnumerable<T>. Como a List<T>é um IEnumerable<T>, você pode simplesmente atribuir a List<T>a uma variável do tipo IEnumerable<T>.

Ao contrário, nem todo IEnumerable<T>é um List<T>offcourse, então você terá que chamar o ToList()método membro do IEnumerable<T>.

Frederik Gheysels
fonte
4
Tecnicamente, ToList é um método membro de System.Linq.Enumerable
Amy B
2
Acho que você pode simplesmente lançar IEnumerable em List como David diz que é.
abatishchev
9

A List<T>já é um IEnumerable<T>, portanto, você pode executar instruções LINQ diretamente em sua List<T>variável.

Se você não vir os métodos de extensão LINQ, como OrderBy()estou supondo, é porque você não tem uma using System.Linqdiretiva no arquivo de origem.

Você precisa converter o resultado da expressão LINQ de volta em um List<T>explicitamente, no entanto:

List<Customer> list = ...
list = list.OrderBy(customer => customer.Name).ToList()
Dan Berindei
fonte
"Se você não vir os métodos de extensão LINQ como OrderBy ()" Esse foi o meu problema, obrigado.
RyPope
5

À parte: Observe que os operadores LINQ padrão (conforme o exemplo anterior) não alteram a lista existente - list.OrderBy(...).ToList()criarão uma nova lista com base na sequência reordenada. É muito fácil, no entanto, criar um método de extensão que permite usar lambdas com List<T>.Sort:

static void Sort<TSource, TValue>(this List<TSource> list,
    Func<TSource, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    list.Sort((x,y) => comparer.Compare(selector(x), selector(y)));
}

static void SortDescending<TSource, TValue>(this List<TSource> list,
    Func<TSource, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    list.Sort((x,y) => comparer.Compare(selector(y), selector(x)));
}

Então você pode usar:

list.Sort(x=>x.SomeProp); // etc

Isso atualiza a lista existente da mesma maneira que List<T>.Sortnormalmente faz.

Marc Gravell
fonte
Uma ligeira correção a esta afirmação: os operadores LINQ padrão não alteram a lista existente; em vez disso, eles criam um novo IEnumerable que contém a lógica necessária para fazer seu trabalho. No entanto, essa lógica não é realmente executada até que o IEnumerator seja solicitado.
Vojislav Stojkovic
@Vojislav - eu queria dizer no contexto do exemplo anterior, terminando com ToList- vou esclarecer, no entanto.
Marc Gravell
1

Convertendo List<T>paraIEnumerable<T>

List<T>implementa IEnumerable<T>(e muitos outros como IList<T>, ICollection<T>), portanto, não há necessidade de converter um List de volta em IEnumerable, pois ele já a IEnumerable<T>.

Exemplo:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Person person1 = new Person() { Id = 1, Name = "Person 1" };
Person person2 = new Person() { Id = 2, Name = "Person 2" };
Person person3 = new Person() { Id = 3, Name = "Person 3" };

List<Person> people = new List<Person>() { person1, person2, person3 };

//Converting to an IEnumerable
IEnumerable<Person> IEnumerableList = people;

Você também pode usar o Enumerable.AsEnumerable()método

IEnumerable<Person> iPersonList = people.AsEnumerable();

Convertendo IEnumerable<T>paraList<T>

IEnumerable<Person> OriginallyIEnumerable = new List<Person>() { person1, person2 };
List<Person> convertToList = OriginallyIEnumerable.ToList();

Isso é útil no Entity Framework .

Nipuna
fonte
0

Para evitar a duplicação na memória, resharper está sugerindo o seguinte:

List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myList as List<string>() ?? myEnumerable.ToList();

.ToList () retorna uma nova lista imutável. Portanto, as alterações em listAgain não afetam myList na resposta do @Tamas Czinege. Isso está correto na maioria dos casos por pelo menos dois motivos: Isso ajuda a evitar mudanças em uma área afetando a outra área (acoplamento fraco) e é muito legível, uma vez que não devemos projetar código com preocupações de compilador.

Mas há certos casos, como estar em um loop apertado ou trabalhar em um sistema embutido ou com pouca memória, onde as considerações do compilador devem ser levadas em consideração.

TamusJRoyce
fonte