自由地在List<T>和IEnumerable<T>之间进行转换

106

如何将List<MyObject>转换为IEnumerable<MyObject>,然后再转换回来?

我想这样做是为了在列表上运行一系列LINQ语句,例如Sort()


这是在此问题中涉及的内容:https://dev59.com/CXVD5IYBdhLWcg3wRpiX - John
6个回答

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

31
请注意,myEnumerable和myList是同一个对象实例,但listAgain并不是与myEnumerable相同的对象实例。根据您想要做什么以及myEnumerable的内容,“List<string> listAgain = myEnumerable as List<string>;”可能更好。 - ChrisW
1
Chrisw:噢,是的,你当然是对的,但 IEnumerable<T> 接口是不可变的,所以它不会在那个方向上引起问题,而且当你有一个函数可以处理类型安全时,强制转换回去只会让人感觉很 - Tamas Czinege
1
你也可以直接使用原始的myList对象。(我想我真的不明白这个问题) - sth
6
如果他编辑myList,那么他就会编辑myEnumerable,但如果他编辑listAgain,那么他就不会编辑myEnumerable。 - ChrisW
15
不要忘记使用 System.Linq,否则您将无法使用 ToList() - Jason
显示剩余2条评论

21

List<T> 是一个 IEnumerable<T>,因此实际上不需要将 List<T> 转换为 IEnumerable<T>。 由于 List<T> 是一个 IEnumerable<T>,所以您可以简单地将 List<T> 分配给类型为 IEnumerable<T> 的变量。

另一方面,不是每个 IEnumerable<T> 都是 List<T>,所以这时需要调用 IEnumerable<T>ToList() 成员方法。


4
ToList 是 System.Linq.Enumerable 的一个成员方法。 - Amy B
2
我认为你可以像David所说的那样,将IEnumerable直接转换为List。 - abatishchev

9
List<T>已经是一个IEnumerable<T>,因此您可以直接在List<T>变量上运行LINQ语句。
如果您没有看到像OrderBy()这样的LINQ扩展方法,我猜测是因为您在源文件中没有using System.Linq指令。
但是,您确实需要明确将LINQ表达式结果转换回List<T>
List<Customer> list = ...
list = list.OrderBy(customer => customer.Name).ToList()

如果您没有看到LINQ扩展方法,例如OrderBy(),那就是您的问题了,谢谢。 - RyPope

5

注意:标准的LINQ操作符(如之前的示例)不会改变现有的列表 - list.OrderBy(...).ToList()将创建一个基于重新排序序列的新列表。然而,很容易创建一个扩展方法,使您可以使用lambda表达式与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 Stojkovic
@Vojislav - 我的意思是在早先的例子中以 "ToList" 结尾的情况下 - 我会进行澄清。 - Marc Gravell

1

List<T>转换为IEnumerable<T>

List<T>实现了IEnumerable<T>(以及许多其他的,如IList<T>, ICollection<T>),因此无需将List转换回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 的更改不会影响 @Tamas Czinege 答案中的 myList。在大多数情况下,这是正确的,原因至少有两个:这有助于防止一个区域的更改影响另一个区域(松耦合),并且非常易读,因为我们不应该使用编译器考虑来设计代码。

但是,在某些情况下,比如在紧密循环或低内存系统上工作时,应该考虑编译器的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接