Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use IQueryable.Count<T> with an IEnumerable<T> parameter

imagine a class, let's say for pagination which could be used with an IList<T> or an IQueryable<T>.

That class would have an int TotalItems property, which would (not that surprising) get / set the count of the queryable or enumerable parameter.

If I use IEnumerable<T> as parameter,

//simplified
public Pagination(IEnumerable<T> query)
    {
        TotalItems = query.Count();
    }

the Count() method will be (if I'm not wrong, that's the point) Enumerable.Count(). So even if query is an IQueryable<T> (which inherits from IEnumerable<T>), it will be enumerated (which is obviously not desired with a "db query").

So is there a way to use Queryable.Count() method when my IEnumerable<T> is in fact an IQueryable<T>, or do I have to change my design, having, for example in this case, 2 ctor

//simplified
public Pagination(IEnumerable<T> query)
    {
         TotalItems = query.Count();
    }
public Pagination(IQueryable<T> query)
    {
         TotalItems = query.Count();
    }

EDIT I do understand that IQueryable<T> inheriting from IEnumerable<T> has nothing to do with the fact that IEnumerable<T> and IQueryable<T> have extension methods with same name, and that it's nice to have same names for extension method, which "look like they do the same", but I think it still sometimes confusing...

Generic question for curiosity

Are they other examples, in framework, with the same "architecture" : inheritance + common names for extension methods ?

like image 514
Raphaël Althaus Avatar asked Mar 08 '13 15:03

Raphaël Althaus


1 Answers

You should have two constructor overloads, as you showed in the question. This makes it up to the caller whether they want the IQueryable methods to be used, or the IEnumerable methods to be used.

If someone were to do:

Pagination pager = new Pagination(query.AsEnumerable());

Then they clearly want the object to be processed as an IEnumearble, not an IQueryable. Perhaps they know that Skip and Take aren't implemented by their query provider and so the pagination will fail, and it needs to be evaluated as Linq-to-objects.

By having the two overloads you make it an informed decision by the user of your class whether they're dealing with an in memory sequence or a query, rather than trying to figure it out on your own.

like image 66
Servy Avatar answered Oct 11 '22 10:10

Servy