您是否有更喜欢在与LINQ查询结果交易时使用的默认类型?
默认情况下,LINQ将返回IEnumerable<>
或IOrderedEnumerable<>
。我们发现List<>
通常对我们更有用,因此大多数时候习惯ToList()
我们的查询,当然在函数参数中使用List<>
并返回值。
唯一的例外是在LINQ to SQL中,调用.ToList()
会过早地枚举IEnumerable
。
我们也在广泛使用WCF,其默认集合类型为System.Array
。我们总是在VS2008的“服务引用设置”对话框中将其更改为System.Collections.Generic.List
,以与我们的其余代码库保持一致。
你做什么?
答案 0 :(得分:23)
ToList
总是立即评估序列 - 而不仅仅是在LINQ to SQL中。如果你想要,那很好 - 但并不总是合适。
就我个人而言,我会尽量避免声明您直接返回List<T>
- 通常IList<T>
更合适,并允许您稍后更改为其他实现。当然,有些操作只在List<T>
本身上指定......这种决定总是很棘手。
编辑:(我会把它放在评论中,但它太笨重了。)延迟执行允许你处理太大而不适合内存的数据源。例如,如果您正在处理日志文件 - 将它们从一种格式转换为另一种格式,将它们上传到数据库中,计算出一些统计数据或类似的东西 - 您可以通过流式传输来处理任意数量的数据,但你真的不想把所有东西都吸进内存。这可能不是您特定应用的关注点,但需要牢记这一点。
答案 1 :(得分:16)
我们有相同的场景 - 与服务器的WCF通信,服务器使用LINQtoSQL。
我们在从服务器请求对象时使用.ToArray(),因为客户端更改列表是“非法的”。 (意思是,没有任何意图支持“.Add”,“。删除”等)。
虽然仍然在服务器上,但我建议您将其保留为默认设置(不是IEnumerable,而是IQueryable)。这样,如果您想根据某些条件进行更多过滤,则在SQL端进行过滤 STILL ,直到进行评估。
这是非常重要的一点,因为它意味着令人难以置信的性能增益或损失取决于你的工作。
实施例
// This is just an example... imagine this is on the server only. It's the
// basic method that gets the list of clients.
private IEnumerable<Client> GetClients()
{
var result = MyDataContext.Clients;
return result.AsEnumerable();
}
// This method here is actually called by the user...
public Client[] GetClientsForLoggedInUser()
{
var clients = GetClients().Where(client=> client.Owner == currentUser);
return clients.ToArray();
}
你看到那里发生了什么吗? “GetClients”方法将强制从数据库中下载所有“客户端”......那么Where子句将在GetClientsForLoogedInUser方法中进行过滤。
现在,请注意稍微的变化:
private IQueryable<Client> GetClients()
{
var result = MyDataContext.Clients;
return result.AsQueryable();
}
现在,直到调用“.ToArray”才会进行实际评估...而SQL将进行过滤。好多了!
答案 2 :(得分:7)
在Linq-to-Objects的情况下,从函数返回List<T>
不像返回IList<T>
那样好,就像VENERABLE SKEET指出的那样。但通常你仍然可以做得更好。如果你要返回的东西应该是不可变的,那么IList是一个糟糕的选择,因为它邀请调用者添加或删除东西。
例如,有时您有一个方法或属性返回Linq查询的结果或使用yield return
懒惰地生成一个列表,然后您意识到最好在第一次执行此操作时执行此操作'调用,将结果缓存在List<T>
中,然后返回缓存版本。返回IList
时可能是个坏主意,因为调用者可能会出于自己的目的修改列表,这会破坏您的缓存,使其更改对所有其他调用者可见。
最好返回IEnumerable<T>
,所以他们只有前向迭代。如果调用者想要快速随机访问,即他们希望他们可以使用[]通过索引访问,他们可以使用ElementAt
,Linq定义它以便它悄悄地嗅探IList
并使用它(如果可用) ,如果没有,它会进行哑线性查找。
我使用ToList
的一件事是当我有一个复杂的Linq表达式系统与使用yield return
来过滤或转换列表的自定义运算符混合时。在调试器中单步执行可能会因为它在执行延迟评估时跳转而变得非常混乱,因此我有时会临时将ToList()添加到几个位置,以便我可以更轻松地遵循执行路径。 (虽然如果你正在执行的事情有副作用,这可能会改变程序的含义。)
答案 3 :(得分:2)
这取决于您是否需要修改集合。当我知道没有人要添加/删除项目时,我喜欢使用数组。我需要排序/添加/删除项目时使用列表。但是,通常我只要把它留作IEnumerable就可以了。
答案 4 :(得分:2)
如果您不需要List&lt;&gt;的附加功能,为什么不坚持使用IQueryable&lt;&gt; ?!?!?!最低的共同点是最好的解决方案(特别是当你看到蒂莫西的回答时)。