Свободное преобразование между List <T> и IEnumerable <T>

103

Как я могу преобразовать a List<MyObject>в a, IEnumerable<MyObject>а затем обратно?

Я хочу сделать это, чтобы запустить серию операторов LINQ в списке, например Sort()

ТЗ.
источник
Это рассматривается в этом вопросе stackoverflow.com/questions/31708/…
Джон,

Ответы:

148
List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myEnumerable.ToList();
Тамаш Чинеге
источник
30
Однако помните, что myEnumarable - это тот же экземпляр объекта, что и myList, но listAgain не является тем же экземпляром объекта, что и myEnumerable. В зависимости от того, что вы хотите сделать и что такое myEnumerable, «List <string> listAgain = myEnumerable as List <string>;» может быть лучше.
ChrisW
1
Крис: О да, вы, конечно, правы, но интерфейс IEnumerable <T> неизменяем, поэтому он не вызовет проблем в этом направлении, а возврат назад просто кажется грязным, когда у вас есть функция, которая позаботится о безопасности типов.
Tamas Czinege
1
Вы также можете просто использовать исходный объект myList. (Думаю, я не совсем понял вопрос)
sth
6
Просто если он редактирует myList, он будет редактировать myEnumrable, но если он редактирует listAgain, он не будет редактировать myEnumerable.
ChrisW
15
Не забывайте, using System.Linq;иначе вы не сможете ToList ()
Джейсон
21

A List<T>- это IEnumerable<T>, поэтому на самом деле нет необходимости «конвертировать» a List<T>в IEnumerable<T>. Поскольку a List<T>- это IEnumerable<T>, вы можете просто присвоить List<T>a переменной типа IEnumerable<T>.

С другой стороны, не все IEnumerable<T>- это List<T>вне курса, поэтому вам придется вызвать ToList()метод-член класса IEnumerable<T>.

Фредерик Гейзель
источник
4
Технически ToList является методом-членом System.Linq.Enumerable
Эми Б.
2
Я думаю, вы можете просто добавить IEnumerable в List, как сказал Дэвид.
abatishchev
9

A List<T>уже является IEnumerable<T>, поэтому вы можете запускать операторы LINQ непосредственно для своей List<T>переменной.

Если вы не видите методы расширения LINQ, как OrderBy()я предполагаю, это потому, что у вас нет using System.Linqдирективы в исходном файле.

Однако вам нужно List<T>явно преобразовать результат выражения LINQ обратно в :

List<Customer> list = ...
list = list.OrderBy(customer => customer.Name).ToList()
Дэн Бериндей
источник
«Если вы не видите методы расширения LINQ, такие как OrderBy ()» Это была моя проблема, спасибо.
RyPope 06
5

Кроме того: обратите внимание, что стандартные операторы LINQ (как в предыдущем примере) не изменяют существующий список - list.OrderBy(...).ToList()они создают новый список на основе переупорядоченной последовательности. Однако довольно легко создать метод расширения, который позволяет использовать лямбды с 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)));
}

Тогда вы можете использовать:

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

Это обновляет существующий список таким же образом, List<T>.Sortкак и обычно.

Марк Гравелл
источник
Небольшая поправка к этому утверждению: стандартные операторы LINQ не изменяют существующий список; вместо этого они создают новый IEnumerable, который содержит логику, необходимую для выполнения их работы. Однако эта логика фактически не выполняется, пока не будет запрошен IEnumerator.
Воислав Стойкович
@Vojislav - я имел в виду в контексте предыдущего примера, заканчивающегося на ToList- я все же поясню.
Марк Гравелл
1

Преобразование List<T>вIEnumerable<T>

List<T>реализует IEnumerable<T>(и многие другие, например IList<T>, ICollection<T>), поэтому нет необходимости преобразовывать список обратно в IEnumerable, поскольку он уже является файлом IEnumerable<T>.

Пример:

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;

Вы также можете использовать Enumerable.AsEnumerable()метод

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

Преобразование IEnumerable<T>вList<T>

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

Это полезно в Entity Framework .

Нипуна
источник
0

Чтобы предотвратить дублирование в памяти, resharper предлагает следующее:

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

.ToList () возвращает новый неизменяемый список. Таким образом, изменения в listAgain не влияют на myList в ответе @Tamas Czinege. Это верно в большинстве случаев по крайней мере по двум причинам: это помогает предотвратить изменения в одной области, влияющие на другую область (слабая связь), и она очень удобочитаема, поскольку мы не должны проектировать код с учетом проблем компилятора.

Но есть определенные случаи, например, нахождение в замкнутом цикле или работа со встроенной системой или системой с низким объемом памяти, где следует учитывать соображения компилятора.

TamusJRoyce
источник