Resharper,“返回类型可以是IEnumerable...”但为什么?

6
我有一个如下所示的接口...
public interface IAccountRepository : IDisposable {
    IQueryable<Account> FindByUserId(int userId); //here, Resharper says "Return type can be IEnumerable<Account>"
}

但是Resharper建议我将其改为IEnumerable<Account> FindByUserId(int userId)

为什么呢?这样做不会强制将整个对象加载到内存中吗?我认为推迟执行直到真正需要对象会更好,不是吗?


3
直到你执行像 .Count().ToList() 这样的方法之前,它才会被加载到内存中。 - Pierre-Luc Pineault
1
@Pierre-LucPineault IQueryable允许进一步细化查询(.Where...),而不会预先将结果加载到内存中的对象中。显然,IEnumerable不具备这种能力,对吗? - Rosdi Kasim
1
@Porges 您是正确的,我的解决方案中还没有使用 IQueryable<T> 方法,但这并不意味着它将来不会被使用,对吧?或者我有什么遗漏吗? - Rosdi Kasim
这个R#文档页面是关于不同的消息,但与之相关的。(http://confluence.jetbrains.com/display/ReSharper/Parameter+type+can+be+IEnumerable+of+T) - ta.speot.is
@TimSchmelter,你提供的链接是关于方法参数的问题,而我问的是关于返回类型的。我想了解为什么Resharper会给我那个建议。 - Rosdi Kasim
显示剩余4条评论
3个回答

9
这只是一个普遍规则的具体实例。
如果你返回的类型是实现接口或继承自另一个类的 SomeClass ,且在整个解决方案中你仅使用基类/接口中声明的方法(不使用 SomeClass 中声明的任何方法),ReSharper 将建议你将返回对象的类型替换为基类/接口的类型,以使你的代码更通用。
在这种情况下,你仅使用了 IQueryable<T> 派生自的 IEnumerable<T> 接口方法。
还要注意这只是一条 建议,不是警告或错误。如果你想忽略它的话也是安全的。

3
+1 Return type can be IEnumerable 简单地意味着返回类型可以IEnumerable,而不是必须是IEnumerable - ta.speot.is
1
谢谢。我只是想确保我理解自己在做什么,而不是盲目地遵循R#的建议。 - Rosdi Kasim

6
答案是“不,但是”。将其转换为IEnumerable并不会强制执行。IEnumerable空间中的运算符(如“Where”方法)仍然可以进行惰性评估。但这里有一些注意事项。如果您在此方法内部开始使用LINQ运算符,则LINQ将选择Enumerable LINQ运算符,例如GroupBy (IEnumerable)而不是IQueryable运算符,例如GroupBy (IQueryable)。请注意它们在参数列表上的区别。这样做的效果是,您传递的Lambda表达式将被转换为Func而不是Expression>(请注意两种方法各自的参数列表的差异)。因此,您的lambda将不是表达式树,这是Queryable源需要将其翻译成SQL(或类似语言)以便查询可以通过服务器并在服务器端执行。因此,您的查询速度将变慢。不是因为它被转换后立即执行,而是因为一旦您开始尝试从中获取项目,整个数据源就会被拉到客户端。

当然,这仅适用于在此方法内开始使用LINQ(附加“Where”子句或其他内容)。如果没有使用,那就没问题。


这意味着我可能会将大量结果移动到内存中进行过滤,对吗?这是我从这个答案中理解的,https://dev59.com/TnE85IYBdhLWcg3wOw_s#2876655 - Rosdi Kasim
1
在此方法内使用的任何LINQ运算符都无法在服务器端执行。 - Tormod
@RosdiKasim 如果您从存储库返回非常大的数据集,那么这是可能的,但您为什么要这样做呢?如果有泄漏的抽象,那么IQueryable就是其中之一,因此您希望尽早限制结果集,并且只在服务层中处理IEnumerable - sara

1

IQueryable 已经继承自 IEnumerable (MSDN),因此您对 IEnumerable 的任何异议仍将存在。ReSharper 指示即使所有实现都返回 IQueryable,该方法也可以定义为返回 IEnumerable(如果调用需要 IQueryable 而不是 IEnumerable,它们也可以调用 AsQueryable MSDN)。

此外,IEnumerable 的成员只在枚举时检索,这意味着例如,即使每个成员都通过单独的 Web 服务调用获得,当请求特定成员时才会进行这些调用。


1
据我所知,它们的行为不同,请参见此答案:https://dev59.com/TnE85IYBdhLWcg3wOw_s#2876655 - Rosdi Kasim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接