118

的目的是AsQueryable()为了让您可以传递一个IEnumerable可能期望的方法IQueryable,还是有一个有用的理由表示IEnumerableIQueryable?例如,是否应该用于以下情况:

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版本是否只是构建了一个表达式,一旦执行,它最终会做同样的事情?我的主要问题是,使用的真正用例是什么AsQueryable

4

5 回答 5

79

有几个主要用途。

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

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

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

于 2013-12-04T15:24:54.210 回答
14

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

不过,我会对它在应用程序代码中的使用位置感兴趣。

于 2013-09-05T21:19:21.513 回答
12

正如 sanjuro 所指出的, AsQueryable() 的目的在将 AsQueryable 与 Linq To Objects 和 Linq To SQL一起使用中进行了解释。文章特别指出,

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

于 2014-03-04T23:38:43.573 回答
7

AsQueryable() 的用途在这篇文章Using AsQueryable With Linq To Objects 和 Linq To SQL中有详细解释

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

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

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

于 2013-12-04T15:13:49.687 回答
4

接口IQueryable引用文档:

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

因此,对于打算在 .NET 中使其数据结构可查询的人来说,可以枚举不需要的数据结构或具有有效的 enumerator

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

于 2013-06-28T14:27:20.693 回答