C# IEnumerable<;T>;作为返回值、延迟执行和N层应用程序 首先,我不认为这个问题是这些问题的原因:

C# IEnumerable<;T>;作为返回值、延迟执行和N层应用程序 首先,我不认为这个问题是这些问题的原因:,c#,ienumerable,ilist,n-tier-architecture,C#,Ienumerable,Ilist,N Tier Architecture,及 众所周知,引入多个层的主要目的之一是减少耦合。 我们必须为数据访问定义一些接口,我们的BL不应该关心DAL实现的细节。如果提到的接口返回IEnumerableBL,则不知道它是静态的IEnumerable还是延迟执行的东西。同时,此特定细节可能会对性能产生很大影响,并且需要根据实现情况进行不同的编码。 好的,在我们要多次迭代集合的情况下,可以为每个IEnumerable调用.ToList()。但由于不必要的新列表实例化,这会降低静态集合的性能 因此,我试图了解哪种方法更好。 与耦合度更高、性

众所周知,引入多个层的主要目的之一是减少耦合。
我们必须为数据访问定义一些接口,我们的BL不应该关心DAL实现的细节。如果提到的接口返回
IEnumerable
BL,则不知道它是静态的
IEnumerable
还是延迟执行的东西。同时,此特定细节可能会对性能产生很大影响,并且需要根据实现情况进行不同的编码。
好的,在我们要多次迭代集合的情况下,可以为每个
IEnumerable
调用
.ToList()
。但由于不必要的新列表实例化,这会降低静态集合的性能

因此,我试图了解哪种方法更好。
与耦合度更高、性能更优的产品相比,通用性更强、潜在性能更低。
我想,没有银弹,但可能是我错过了其他方法。

如果从概念上讲,调用方知道方法的返回类型是一个
列表,而不是
IEnumerable
(例如,知道多次迭代不会产生负面后果),那么这一点很重要,然后您应该返回一个
列表
。相反,返回接口的目的是说,“实现是什么并不重要。”如果实现是重要的,那么不要使用接口(在特定情况下)

因此,我试图了解哪种方法更好:更通用、性能更低,而不是更耦合、性能更高

首先,尽管这是一个有趣的权衡,但在本例中,我认为相关的权衡实际上是正确的与错误的,这肯定胜过任何性能问题。延迟执行查询通常具有这样的属性:它为您提供查询的最新结果,而调用
ToList
则为您提供查询结果过去版本的快照。当然,在某些情况下,一个是正确的,另一个是错误的

第二,假设您已经处理了正确性问题,并且确实需要进行性能权衡,那么您实际想要进行的权衡是:更通用且不可接受的性能与更耦合且可接受的性能,在这一点上,您必须选择性能可接受的


如果两者都具有可接受的性能,并且其中一个比另一个慢几纳秒,或者比另一个多消耗几个字节的内存,并且两者都是正确的,那么谁在乎您选择哪一个呢?把你宝贵的时间花在思考其他事情上。如果两者都没有可接受的性能,那么您就有一个更大的问题要解决。

我找到了一个好的解决方案:DAL中的所有返回类型(接口中)都不能是
IEnumerable
(或者不能是接口类型)。但是可以在BL中使用。这可能是架构师的决定。

请注意,如果使用foreach迭代IEnumerable,实际上是列表或普通数组,速度非常快。该实现进行了一些优化。(你可以用秒表计时来验证这一点。)对我来说,这似乎是重复的。特别是你联系的第二个问题。这个问题的公认答案很好地解决了你的担忧。关键是,“视情况而定”。如果延迟执行会导致性能问题,那么让DAL返回一个具体列表。如果您在.Net 4.5上,可以使用
IReadOnlyList
@Jimmischel。我同意,但如果我们想提供模块化和可变性,我们怎么能从DAL中得到比仅仅一个接口更多的东西呢?“知道对IEnumerable进行多次迭代不会产生负面影响”。你是什么意思?@Tigran可以想象,
IEnumerable
在多次迭代时可能返回完全不同的结果,或者可能涉及查询数据库或执行计算密集型任务。因此,当给定一个来自未知源的
IEnumerable
时,最好避免不惜一切代价重复多次。在某些情况下,这意味着将序列放入一个列表中,这样您就可以确保多次迭代不会产生那些(可能不需要的)副作用。如果它已经是一个列表,那么你只是做了不必要的工作。返回一个列表有它自己的担忧。。。例如,干将做了防御性的复制吗?@MatthewWatson肯定。这并不意味着你不应该从任何方法返回列表。@Servy:我明白了,你说的是声明性意图,但是OP在其应用程序中询问了具体的权衡(可能的权衡)。所以你的答案并没有真正回答他的问题。声明IEnumerable定义了定义数据流的意图,但这并不意味着您可以或不应该对其进行多次迭代,因为这完全取决于实现细节。所以问题是:如何更好地设计返回/传递值,以避免将来不同层之间的可伸缩性问题。不幸的是,世界并不理想,我们必须在架构的开放性(我们需要解决根本性需求变化的努力越少越好)和YAGNI之间保持平衡。我认为这是猜测和经验的混合体,有助于区分正确和错误。这里我要补充的是,IEnumerable在数据请求方面留下了一些灵活性的概念。如果我们将BL视为客户机的CRUD层,IEnumerable允许客户机请求特定数据。因此,我们可以保持BL的简单性,而不必为不同的数据读取场景使用一系列方法来膨胀它