我想知道以下事实。我有一个数据存储库,它返回IEnumerable<Customer>
的所有数据。
在我的业务逻辑中,有时候我需要列表,所以我可以添加一些东西。
当我检索IEnumerable<Customer>
时,我有2个选项可以从中获取列表。
使用Linq扩展方法.ToList()
或投射它(我认为它不是转换),如(List<Customer>)IEnumerable<Customer>
。
必须提到我不使用列表进行迭代,所以每次都不需要我的枚举的新副本。在这种情况下,在我的简单情况下,我必须使用强制转换方法而不是.ToList
(创建新副本)吗?
// use simple cast?
List<Customer> customers = (List<Customers>)DataSource.GetCustomers();
// or if i use this i get a bit of performance loss?
List<Customer> customers = DataSource.GetCustomers().ToList();
答案 0 :(得分:5)
我选择ToList()
,因为该方法会返回IEnumerable<Customer>
,但您无法确定内部实现。
现在可能GetCustomers()
会返回List<>
屏蔽的IEnumerable<>
,但如果将来内部实施发生变化会怎样?
编辑:
List<Customer>
实现了接口IEnumerable<Customer>
,以及Customer[]
或LinkedList<Customer>
等数组。因此,当您收到IEnumerable<WhateverClass>
类型的对象时,您无法确定它是List<Customer>
,当然,仅当您要转换为的类型在界面后面时,该转换才有效,否则你会收到例外。
使用ToList()
,正如您所说,您创建了一个包含IEnumerable<>
元素的新对象,但至少可以安全地迭代/修改该对象,而不会有任何例外。
这些方法返回IEnumerable<T>
,因为这样它就不会绑定到任何特定的集合实现,并且将来它可以在不改变方法签名的情况下从列表切换到数组等等......
答案 1 :(得分:2)
这取决于。如果大小很小,我会使用.ToList(),但你必须明白这将会复制列表。
如果它很大或者你正在做很多事(它会造成性能损失)你可以检查.GetCustomers()返回的对象是否是一个列表 如果是 - 强制转换,则使用.ToList()创建副本。
答案 2 :(得分:1)
我建议使用.ToList()。它会表现得更糟,但是如果你使用了有关API实现细节的信息,那么你就会做出无根据的假设。明天有人会将IEnumerable更改为不是列表的内容,并且您的代码将开始抛出异常。
答案 3 :(得分:1)
您可以通过使用条件来使用强制转换,以防止将来的实施更改。像
这样的东西List<Customer> customers = null;
try
{
customers = (List<Customers>)DataSource.GetCustomers();
}
catch
{
customers = DataSource.GetCustomers().ToList();
}
这样,只要IEnumerable是一个列表,就可以避免复制列表,但是如果由于某种原因,将来内部实现发生变化,你的代码将继续工作。
答案 4 :(得分:0)
您的存储库返回IEnumerable的重点是它不能保证实际上是一个列表。 (可能现在,但IEnumerable的使用允许稍后更改实现。)
使用.ToList()方法,或者让存储库返回List或IList。