AsQueryable()的目的是什么?

时间:2013-06-28 14:21:38

标签: c# .net linq ienumerable iqueryable

AsQueryable()的目的是否只是为了让IEnumerable传递给可能期望IQueryable的方法,或者有一个有用的理由将IEnumerable表示为{ {1}}?例如,它应该是这样的情况:

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

的真实用例是什么?

5 个答案:

答案 0 :(得分:56)

有一些主要用途。

  1. 如其他答案中所述,您可以使用它来使用内存数据源模拟可查询数据源,以便您可以更轻松地测试最终将在基于不可枚举的{{{ 1}}。

  2. 您可以编写辅助方法来操作可应用于内存中序列或外部数据源的集合。如果您编写帮助方法以完全使用IQueryable,则可以在所有枚举上使用IQueryable来使用它们。这样可以避免编写非常通用的辅助方法的两个单独版本。

  3. 它允许您将可查询的编译时类型更改为AsQueryable,而不是更多派生类型。有效;您将IQueryableIQueryable AsEnumerable同时使用IEnumerable。您可能有一个实现IQueryable的对象,但也有一个实例Select方法。如果是这种情况,并且您想使用LINQ Select方法,则需要将对象的编译时类型更改为IQueryable。您可以直接投射,但通过AsQueryable方法,您可以利用类型推断。如果泛型参数列表很复杂,这样会更方便,如果任何泛型参数是匿名类型,它实际上是必需的

答案 1 :(得分:10)

我对AsQueryable最有效的案例是单元测试。说我有以下有点人为的例子

public interface IWidgetRepository
{
   IQueryable<Widget> Retrieve();
} 

public class WidgetController
{
   public IWidgetRepository WidgetRepository {get; set;}


   public IQueryable<Widget> Get()
   {
      return WidgetRepository.Retrieve();
   }
}

我想写一个单元测试来确保控制器传回从存储库返回的结果。它看起来像这样:

[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()方法允许我做的是在设置模拟时满足编译器。

我对应用程序代码中使用它感兴趣。

答案 2 :(得分:8)

正如sanjuro所说,AsQueryable()的目的在Using AsQueryable With Linq To Objects And Linq To SQL中解释。特别是,文章指出,

  

这在真实单词场景中提供了极好的好处,在这些场景中,您在实体上有某些方法,这些方法返回T的IQueryable并且某些方法返回List。但是你有业务规则过滤器需要应用于所有集合,无论集合是作为T的IQueryable还是从Tn的IEnumerable返回的。从性能角度来看,你真的想利用在数据库上执行业务过滤器该集合实现了IQueryable,否则回退到使用Linq将业务过滤器应用于内存中以对象代表的实现。

答案 3 :(得分:3)

本文Using AsQueryable With Linq To Objects And Linq To SQL

中详细解释了AsQueryable()的用途

来自MSDN Queryable.AsQueryable方法的备注部分:

  

如果源类型实现IQueryable,则AsQueryable(IEnumerable)直接返回它。否则,它返回一个IQueryable,它通过调用Enumerable中的等效查询运算符方法而不是Queryable中的方法来执行查询。

这就是上面提到和使用的内容。 在您的示例中,它取决于orderRepo.GetAll返回的内容,IEnumerable或IQueryable(Linq to Sql)。如果它返回IQueryable,则将在数据库上执行Count()方法,否则它将在内存中执行。请仔细阅读参考文章中的示例。

答案 4 :(得分:2)

接口IQueryable引用文档:

  

IQueryable接口旨在通过查询实现   提供者。

因此,对于打算在.NET中查询其数据收缩的人,可以枚举不必要的数据结构或具有有效的枚举器

IEnumerator是用于迭代和处理数据流的接口。