15

想象一个类,假设分页可以与 anIList<T>或 an一起使用IQueryable<T>

该类将具有一个int TotalItems属性,它将(并不奇怪)获取/设置可查询或可枚举参数的计数。

如果我IEnumerable<T>用作参数,

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

Count()方法将是(如果我没记错的话,这就是重点Enumerable.Count()。因此,即使查询是一个IQueryable<T>(继承自IEnumerable<T>),它也会被枚举(这显然不是“数据库查询”所希望的)。

那么当我实际上是一个时,有没有办法使用Queryable.Count()方法,或者我是否必须改变我的设计,例如在这种情况下,有 2 ctorIEnumerable<T>IQueryable<T>

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

编辑 我确实理解IQueryable<T>继承与具有相同名称的扩展方法IEnumerable<T>这一事实无关,IEnumerable<T>并且IQueryable<T>扩展方法具有相同的名称是很好的,“看起来它们做的一样”,但我认为它仍然有时会混淆...

好奇心的一般问题

它们是否是框架中具有相同“架构”的其他示例:继承+扩展方法的通用名称?

4

2 回答 2

8

正如问题中所示,您应该有两个构造函数重载。这由调用者决定是否要使用IQueryable方法或要使用的IEnumerable方法。

如果有人这样做:

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

然后他们显然希望将对象处理为IEnumearble,而不是IQueryable。也许他们知道这一点Skip并且Take没有由他们的查询提供程序实现,因此分页将失败,并且需要将其评估为 Linq-to-objects。

通过使用这两个重载,您可以让您的类的用户做出明智的决定,无论他们是在处理内存中的序列还是查询,而不是试图自己弄清楚。

于 2013-03-08T16:33:39.893 回答
1

好吧,你可以这样做:

TotalItems = enumerable.AsQueryable().Count();

这将直接将查询提供程序的Count实现用于本机可查询,或者回退到 LINQ to Objects(使用 时会产生一些开销EnumerableQuery),否则。

另一种解决方案(可能更有效):

var queryable = enumerable as IQueryable<T>;
TotalItems = queryable != null ? queryable.Count() : enumerable.Count();

但是,请注意,如果您的可查询实现ICollectionICollection<T>有效(如某些查询提供程序的情况),即使您现有的解决方案也可能会因为 LINQ 中的优化而工作良好(它Count尽可能使用这些接口中的属性)。对于您的IList<T>,它将始终使用此优化,因为它实现了ICollection<T>.

于 2013-03-08T15:37:46.943 回答