2013-07-27 31 views
6

我有一个接口,这样的...Resharper,“返回类型可以IEnumerable ...”但为什么?

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()'等方法,才会将其加载到内存中。 –

+0

这将是因为你的解决方案没有在'FindByUserId'返回的对象上使用任何'IQueryable '方法,所以R#建议你可以使返回类型更一般化。 – porges

+1

@ Pierre-LucPineault IQueryable允许在不预先将结果加载到内存中的对象的情况下进一步细化查询('.Where ...')。显然这不是IEnumerable的情况吧? –

回答

8

这是一般规则的只是一个特定实例。

如果您要返回的类型为SomeClass,它实现了一个接口或从另一个类继承,并且在整个解决方案中,您只使用基类/接口中返回的对象上的方法(因此您不使用任何方法在SomeClass中声明),ReSharper会建议你将返回的对象的类型替换为基类/接口的类型,以使代码更一般化。

在这种情况下,您只使用IQueryable<T>派生自的IEnumerable<T>接口的方法。

还请注意,这只是一个建议,而不是一个警告或错误。如果你愿意,你可以放心地忽略这个。

+3

+1 *返回类型可以是'IEnumerable' *只是意味着返回类型*可以*是' IEnumerable'不是它*应该*。 –

+1

谢谢..我只是想确保我明白我在做什么,而不是盲目地遵循R#建议。 –

1

IQueryable已从IEnumerableMSDN)继承,因此您对IEnumerable的任何异议仍将存在。 ReSharper的是表明该方法可能也被定义为返回IEnumerable即使全部实现返回IQueryable(如果呼叫需要一个IQueryable而不是IEnumerable,他们可以叫AsQueryableMSDN

也是一个IEnumerable的成员只能当它们被枚举时被检索,这意味着例如即使每个成员是通过单独的Web服务调用获得的,这些调用也只会在请求特定成员时才会发生。

+1

从我的理解,他们的行为不同,看到这个答案︰http://stackoverflow.com/a/2876655/193634 –

6

答案是 “没有,”。

它铸造于IEnumerable的不强制执行。 IEnumerable空间中的运算符(如“Where”方法)仍然可以进行懒惰评估。

但这里是一些警告。如果你在这个方法中开始使用LINQ操作符,那么LINQ将选择可枚举的LINQ操作符,如GroupBy (IEnumerable)而不是Queryable操作符,如GroupBy (IQueryable)。注意他们的参数列表不同。

这样做的效果是,您传递的Lambda表达式将转换为Func而不是Expression>(注意两个方法的参数列表中的差异)。所以你的lambda不会是一个表达式树,这是Queryable源为了将它翻译成SQL(或类似的)所需要的,以便查询可以通过服务器传递并执行服务器端。

所以,你的查询会比较慢。不是因为它会在你投射它之后执行,而是因为一旦你开始尝试从中删除项目,整个数据源将被拖到客户端。

这当然只有在这个方法内部开始使用LINQ(附加“Where”子句或者其他)。如果你不这样做,你很好。

+0

这意味着我可能会疯狂地将大量的结果转移到内存中进行过滤吗?这是我从这个答案了解,http://stackoverflow.com/a/2876655/193634 –

+1

您在此方法中使用的任何LINQ操作符将无法执行服务器端。 – Tormod

+0

@RosdiKasim如果你从你的仓库中返回疯狂的大数据集,那么你可能会这样做吗? “IQueryable”是一个漏洞抽象,如果有的话,所以你想尽可能早地限制结果集,只处理服务层中的IEnumerable。 – kai

相关问题