C# 我的服务应该返回什么接口?可计算的,可计算的,可计算的?

C# 我的服务应该返回什么接口?可计算的,可计算的,可计算的?,c#,.net,C#,.net,假设我有一个SearchService层,它有一个方法来搜索所有以某个字符串开头的汽车 public static class Searcher{ public IAnInterface<Car> CarsStartingWith(string startWith){ //magic } } 公共静态类搜索器{ 公共接口CarsStartingWith(字符串startWith){ //魔力 } } 我的服务应该使用什么接口? IQueryable

假设我有一个SearchService层,它有一个方法来搜索所有以某个字符串开头的汽车

public static class Searcher{
    public IAnInterface<Car> CarsStartingWith(string startWith){
        //magic
    }
}
公共静态类搜索器{
公共接口CarsStartingWith(字符串startWith){
//魔力
}
}
我的服务应该使用什么接口?
IQueryable可以在我的应用程序的其余部分中渲染一个漂亮的流体界面。
IEnumerable具有懒惰的特性。
IList是最实用的

我希望我的所有服务都返回相同的接口,以确保一致性,从而使整个过程更加轻松。

ICollection也可能是一个选项,但它提供的功能太少了…

我会选择IEnumerable,因为它在框架中占据更重要的位置,为需要它的人提供了多功能性,同时也为那些还没有接触到LINQ之类的东西的人提供了熟悉性。

IQueryable
对它的要求相当高——例如,您不能返回数组


通常对我来说,在
IEnumerable
IList
之间的选择通常是在标准情况下更容易实现的选项。

简短回答:这取决于具体情况

更详细的回答:返回您的客户机代码需要的最丰富的类型。如果不需要延迟加载,IList在大多数情况下都可以工作。您仍然可以使用Linq查询IList或IEnumerable。如果需要延迟加载,则使用IEnumerable或IQueryable


旁注:为所有服务返回相同的接口似乎是一个崇高的目标,但考虑到不同的客户端使用模式,您可能需要返回不同的接口。

如果您希望所有服务返回相同的接口,那么我可能会选择
IEnumerable

您的呼叫者可以很容易地转换为
IQueryable
或创建
列表,如果需要:

IEnumerable<Car> cars = Searcher.CarsStartingWith("L");
var carsList = cars.ToList();
var queryableCars = cars.AsQueryable();
IEnumerable cars=Searcher.CarsStartingWith(“L”);
var carsList=cars.ToList();
var queryableCars=cars.AsQueryable();

除非你有严重的理由不这样做,否则一定要使用
IEnumerable
。然后可以使用
yield return
实现getter

IQueryable
是一个完全不同的鱼缸。这不是作为典型内存容器的替代品随便实现的


在其余部分中,
IEnumerable
与其他部分有一个主要区别:它是只读的。

我的经验法则如下:

如果有机会,我可以使用例程的核心算法,并以一种可以使用收益率的方式对其进行重构,我将使用IEnumerable

例如,如果我当前的实现在内部使用数组或列表,但我知道,至少在理论上,我可能希望并且能够在内部对其进行修改以进行惰性求值,那么我将返回一个IEnumerable

我发现返回IEnumerable的好处绝对值得使用它

但是,如果该算法在返回之前需要对结果进行全面评估(虽然很少,但确实会发生),我将使用ILST。基本上,如果我已经在计算它,我会返回它。IList实现了IEnumerable,因此所有与LINQ相关的用例仍然可以工作,但是您将丢失延迟求值。如果我已经被迫提前评估,那也不是问题

我很少回来。我唯一会使用这个接口的时候是直接创建一个可查询的数据访问层,或者类似的东西。在大多数情况下,使用它的开销不值得获得收益


但是,如果您的目标是始终使用单个接口(我不一定同意这个目标),我会坚持使用IEnumerable。

如果您使用IQueryable作为返回类型,您就有一个抽象泄漏的服务层。

我喜欢IEnumerable,只要有办法给它一个Count方法。我知道这是天生的懒惰不知道有多少,但计数属性只是你需要这么多次!LINQ为IEnumerable提供了计数扩展方法。@Jeff如果原始文件是IQueryable(它将被检索和计数),这不是一个好主意。这是真的,但问题不是这样的。任何延迟执行都会使这一点变得困难。任何计数都可能进行检索,无论接口如何,因此我认为您的观点是没有意义的,因为需要计数属性。到目前为止,我也是如此。但我正在努力使我的编程风格更加一致。我想我应该加入IQueryable,因为流体接口通常看起来非常可读。是的,也许一个命名约定取决于惰性/非惰性可能会很有趣。我想反过来说。IList提供了比IEnumerable更多的方法,所以您应该选择IEnumerable,而不考虑延迟求值,除非您需要添加、删除和索引等其他方法。完全同意。您应该始终使用所需的最低合同。正如您所演示的,IEnumerable可以被许多BCL类型使用或转换。True。我决定回来。如果IList在特定情况下更有意义,我将使用命名约定使这些方法从人群中脱颖而出。返回
IEnumerable
的问题是,如果您决定将其转换为
IQuerable
,您将不再查询数据库,而是查询内存中的对象。正如James Curran指出的,
IQueryable
有点大,但在我的大多数场景中,我发现提供可查询的回退更好,让消费者决定是否将其向下转换为IEnumerable。将返回值转换为IEnumerable并不会使其成为只读的:被调用方可以再次将其向后转换。如果需要只读,请在返回结果之前将其包装在只读集合中(例如,使用List(T).AsReadOnly)。我通常都是r