AsQueryable()的目的是什么?
AsQueryable()
的目的只是为了让你可以将IEnumerable
传递给可能期望IQueryable
方法,还是有一个有用的理由将IEnumerable
表示为IQueryable
? 例如,它应该是这样的情况:
IEnumerable<Order> orders = orderRepo.GetAll(); // I don't want to create another method that works on IEnumerable, // so I convert it here. CountOrders(orders.AsQueryable()); public static int CountOrders(IQueryable<Order> ordersQuery) { return ordersQuery.Count(); }
还是它实际上使它做了不同的事情:
IEnumerable<Order> orders = orderRepo.GetAll(); IQueryable<Order> ordersQuery = orders.AsQueryable(); IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3); IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3); // Are these executed in a different way? int result1 = filteredOrders.Count(); int result2 = filteredOrdersQuery.Count();
这些扩展方法的IQueryable
版本是否构build了一个expression式,一旦它被执行,最终会做同样的事情呢? 我的主要问题是,什么是使用AsQueryable
真正的用例?
有几个主要用途。
-
正如其他答案中提到的那样,您可以使用它来使用内存数据源来模拟可查询的数据源,以便您可以更轻松地testing最终将用于基于非可枚举的
IQueryable
。 -
您可以编写帮助程序方法来处理可应用于内存序列或外部数据源的集合。 如果你编写你的帮助方法来完全使用
IQueryable
你可以在所有可枚举AsQueryable
上使用AsQueryable
来使用它们。 这样可以避免编写非常广义的辅助方法的两个单独版本。 -
它允许您将可查询的编译时types更改为
IQueryable
,而不是更多的派生types。 有效; 你可以在一个IQueryable
上使用它,就像在IEnumerable
上使用AsEnumerable
。 你可能有一个实现IQueryable
的对象,但也有一个实例Select
方法。 如果是这种情况,并且您想要使用LINQSelect
方法,则需要将该对象的编译时间types更改为IQueryable
。 你可以投它,但通过一个AsQueryable
方法,你可以利用types推断。 如果generics参数列表是复杂的,那么这样做更简单,而且如果任何generics参数都是匿名types的话,这实际上是非常必要的 。
我对AsQueryable最有效的情况是unit testing。 假设我有以下有些人为的例子
public interface IWidgetRepository { IQueryable<Widget> Retrieve(); } public class WidgetController { public IWidgetRepository WidgetRepository {get; set;} public IQueryable<Widget> Get() { return WidgetRepository.Retrieve(); } }
我想写一个unit testing,以确保控制器返回从存储库返回的结果。 它看起来像这样:
[TestMethod] public void VerifyRepositoryOutputIsReturned() { var widget1 = new Widget(); var widget2 = new Widget(); var listOfWidgets = new List<Widget>() {widget1, widget2}; var widgetRepository = new Mock<IWidgetRepository>(); widgetRepository.Setup(r => r.Retrieve()) .Returns(listOfWidgets.AsQueryable()); var controller = new WidgetController(); controller.WidgetRepository = widgetRepository.Object; var results = controller.Get(); Assert.AreEqual(2, results.Count()); Assert.IsTrue(results.Contains(widget1)); Assert.IsTrue(results.Contains(widget2)); }
在那里,所有的AsQueryable()方法都允许我在设置模拟器时满足编译器。
不过,我会对应用程序代码中使用的位置感兴趣。
正如sanjuro指出的,AsQueryable()的目的在使用AsQueryable与Linq To Objects和Linq To SQL中解释 。 文章特别指出,
这提供了一个真正的字的情况下,你有一个实体返回一个IQueryable的T和一些方法返回列表的某些方法的一个很好的好处。 但是,你有业务规则filter需要应用于所有的集合,无论集合是否返回T的T或IEnumerable T的IQueryable。从性能的angular度来看,你真的想要利用执行数据库上的业务filterif该集合实现IQueryable,否则回退应用业务filter在内存中使用Linq来对象实现的代表。
接口IQueryable
引用文档:
IQueryable接口旨在供查询提供者实现。
因此,对于有意在.NET中进行数据结构查询的人来说,那些不必要的数据结构可以枚举或者具有有效的枚举数 。
IEnumerator
是一个迭代和处理数据stream的接口。
AsQueryable()的目的在本文中有很大的解释, 使用AsQueryable与Linq To Objects和Linq To SQL
从MSDN Queryable.AsQueryable方法的备注部分:
如果源types实现了IQueryable,AsQueryable(IEnumerable)直接返回它。 否则,它会返回一个IQueryable,它通过调用Enumerable中的等价查询操作符方法而不是Queryable中的方法来执行查询。
这正是上面提到和使用的文章。 在你的例子中,它取决于orderRepo.GetAll返回什么,IEnumerable或IQueryable(Linq to Sql)。 如果它返回IQueryable,则Count()方法将在数据库上执行,否则将在内存中执行。 在参考文章中仔细看例子。