Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resharper, "Return type can be IEnumerable..." but why? [duplicate]

Tags:

c#

resharper

I have an interface like so...

public interface IAccountRepository : IDisposable {
    IQueryable<Account> FindByUserId(int userId); //here, Resharper says "Return type can be IEnumerable<Account>"
}

But Resharper is suggesting me to change it to IEnumerable<Account> FindByUserId(int userId) instead.

Why is that so? Wouldn't it force the entire objects to be loaded into memory? I thought it would be better to defer the execution until the object is really needed?

like image 828
Rosdi Kasim Avatar asked Jul 27 '13 22:07

Rosdi Kasim


3 Answers

This is just a specific instance of a general rule.

If you are returning a type SomeClass which implements an interface or inherits from another class, and in your entire solution you only use methods on the returned object which are in the base class/interface (so you don't use any methods declared in SomeClass), ReSharper will suggest that you replace the type of the returned object with that of the base class/interface in order to make your code more general.

In this case, you are only using methods of the IEnumerable<T> interface that IQueryable<T> derives from.

Note also that this is just a suggestion, not a warning or an error. You can safely ignore this if you want to.

like image 85
porges Avatar answered Nov 08 '22 19:11

porges


The answer is "no, BUT".

Casting it to IEnumerable does not force execution. Operators in the IEnumerable space (like the "Where" method) can still be lazily evaluated.

But there is some caveat here. If you, inside this method, start to use LINQ operators, then LINQ will choose the Enumerable LINQ operators like GroupBy (IEnumerable) instead of Queryable operators like GroupBy (IQueryable). Notice that they differ in their parameter list.

The effect of this is that your passed Lambda expression will be converted to a Func instead of an Expression> (note the difference in the parameter list of the two respective methods). So your lambda will not be an expression tree, which is what Queryable sources need in order to translate it to SQL (or similar) so that the query can be passed over the server and executed server side.

So, your query will be slower. Not because it will execute once you cast it, but because the whole datasource will be pulled over to the client once you start trying to get items off of it.

This is, of course, only if start using LINQ (attaching "Where" clauses or something) inside this method. If you don't, you're fine.

like image 24
Tormod Avatar answered Nov 08 '22 18:11

Tormod


IQueryable already inherits from IEnumerable (MSDN), so any objection that you have to IEnumerable will still be there. ReSharper is indicating that the method might as well be defined to return IEnumerable even if all implementations return IQueryable (if a call needed an IQueryable instead of an IEnumerable they can just call AsQueryable too MSDN)

Also members of an IEnumerable are only retrieved as they are enumerated, which means that e.g. even if each member was obtained by a separate web service call, those calls will only be made when the particular member is requested.

like image 1
Nameless One Avatar answered Nov 08 '22 18:11

Nameless One