在我的ASP.net MVC4 Web应用程序中,我使用IEnumerables,试图遵循这一口头禅来编程接口,而不是实现。
Return IEnumerable(Of Student)
与
Return New List(Of Student)
人们告诉我使用List而不是IEnumerable,因为列表会强制执行查询,而IEumerable不会。
这真的是最佳做法吗?有没有其他选择?我对使用可以使用界面的具体对象感到奇怪。我的奇怪感觉合理吗?
在我的ASP.net MVC4 Web应用程序中,我使用IEnumerables,试图遵循这一口头禅来编程接口,而不是实现。
Return IEnumerable(Of Student)
与
Return New List(Of Student)
人们告诉我使用List而不是IEnumerable,因为列表会强制执行查询,而IEumerable不会。
这真的是最佳做法吗?有没有其他选择?我对使用可以使用界面的具体对象感到奇怪。我的奇怪感觉合理吗?
Answers:
有时候,ToList()
对linq进行查询对于确保查询按时间和顺序执行可能很重要。但是,这些情况很少见,在真正遇到它们之前,没有人应该担心太多。
长话短说,IEnumerable
只要在需要迭代的地方就可以使用,IList
在需要直接建立索引并且需要动态大小的数组时使用(如果需要在固定大小的数组上建立索引,则只需使用标准数组即可)。
至于执行时间,您始终可以将列表用作IEnumerable
变量,因此可以IEnumerable
通过执行来随意返回an .ToList();
,也可以通过在on处IEnumerable
执行参数来传入参数as,然后立即强制执行。请注意,每次强制执行时,都不要停留在刚刚执行该操作的变量上并再次执行它,否则最终将不必要地使LINQ查询中的迭代次数加倍。.ToList()
IEnumerable
.ToList()
IEnumerable
关于MVC,这里确实没有什么特别需要注意的。它将遵循与.NET其余部分相同的执行时间规则,我想您可能曾经因过去的延迟执行语义而被混乱所困扰,并将其归咎于MVC告诉您,这在某种程度上是相关的,但是不。延迟执行的语义起初会使每个人感到困惑(甚至在之后的一会儿;它们可能有点棘手)。再说一次,只是不用担心,直到您真正关心确保LINQ查询不会被执行两次或要求它相对于其他代码按一定顺序执行时,才将变量分配给它自己.ToList()强制执行,您会没事的。
List
-绕过一个List
隐含含义,即列表的内容将被修改。如果要返回集合,请使用IReadOnlyCollection
。List
用于方法内部,以及在修改列表的方法之间进行交换。而已!
有两个问题。
IENumerable<Data> query = MyQuery();
//Later
foreach (Data item in query) {
//Process data
}
在到达“过程数据”循环时,查询可能不再有效。例如,如果查询是在已被Dispose的DataContext上运行的,则您的代码将引发异常。当您在与创建它的位置不同的上下文中处理查询时,这种事情变得非常混乱。
第二个问题是,在“过程数据”循环完成之前,不会释放您的连接。如果“过程数据”很复杂,这只是一个问题。在http://msdn.microsoft.com/zh-cn/library/bb386929.aspx中提到了这一点:
问:我的数据库连接保持打开状态有多长时间?
答:在您使用查询结果之前,连接通常保持打开状态。如果您希望花些时间来处理所有结果并且不反对缓存结果,则将ToList应用于查询。在每个对象仅处理一次的常见方案中,流模型在DataReader和LINQ to SQL中都比较出色。
因此,这些问题就是为什么鼓励您确保例如通过调用来实际执行查询ToList()
。但是,正如Jimmy建议的那样,没有什么阻止您将列表作为IEnumerable返回。
通常,我建议避免对IEnumerable进行多次迭代。假设您的代码使用者遵循此规则,那么我认为不必担心有人通过两次执行查询来两次访问数据库。
IEnumerable
尽早枚举的另一个好处是在适当的位置会抛出异常。这有助于调试。
例如,如果您在一个Razor视图中有一个死锁异常,那么它就不会像在您的一种数据访问方法期间发生异常那样清楚。
IEnumerable
可以抛出的方法都可能会出错。延迟IEnumerable
方法应分为两种:一种非延迟方法检查参数并进行设置,并在必要时抛出(例如,由于参数为空)。然后,它返回到其私有实现的呼叫被推迟。我认为我的评论与您的答案完全不符,但确实认为您在答案中遗漏了一个重要方面,即使用IEnumerable
vs. List
(变异)vs. IReadOnlyCollection
(推迟)。