AsQueryable()的目的是什么?


106

这样做的目的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

Answers:


65

有一些主要用途。

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

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

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


感谢复兴。因为它是最完整的,所以将其标记为答案。
Ocelot20年

5
鉴于这IQueryable<T>源自于IEnumerable<T>您能否解释“基于不可枚举的IQueryable”的含义?

2
@Dai所指的IQueryable不只是包装的IEnumerable,而且实际上利用了的附加功能IQueryable
Servy

#1正是我想要的。感谢您的验证。
one.beat.consumer

12

我对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()方法允许我做的就是使编译器满意。

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


11

如sanjuro所述,AsQueryable()的用途已在使用Linq To Objects和Linq To SQL使用AsQueryable进行了说明。该文章特别指出,

这在真实的单词场景中提供了极大的好处,在这种情况下,您在实体上有某些方法可以返回T的IQueryable,而某些方法可以返回List。但是,那么无论将集合作为T的IQueryable还是T的IEnumerable返回,都需要对所有集合应用业务规则过滤器。从性能的角度来看,如果在以下情况下,您确实想利用对数据库执行业务过滤器集合将实现IQueryable,否则将回退以使用Linq将委托中的对象实现应用于内存中的业务过滤器。


6

本文将AsQueryable()的目的在Linq To Objects和Linq To SQL中结合使用进行了详细说明

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

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

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


3

接口IQueryable引用文档:

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

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

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


您介意将其改写为:“可以枚举不需要的数据结构或具有有效的枚举数”。我明白之间的差别IQueryableIEnumerable,但我不明白的用例AsQueryable扩展方法。不过,我对这句话有点不满意,我怀疑这可能是我想要的答案(基于投票)。
Ocelot20 2013年

@ Ocelot20:这意味着由实现IQueryable的提供程序提供的帽子数据结构可能无法提供枚举功能。由供应商决定。引用文档:“调用Execute方法时,将执行不返回可枚举结果的查询。”
Tigran 2013年

也许我遗漏了一些明显的东西,但是我仍然看不到“为什么需要使用AsQueryable()?” 的答案。如果我 IEnumerable(已经可以提供枚举功能)开始,为什么我需要转换为IQueryable使用扩展方法AsQueryable()?也许是一个小的代码示例来说明这会派上用场吗?我似乎在您的解释中遗漏了一些东西。谢谢你的时间。
Ocelot20年

@ Ocelot20:要真正显示差异,我需要编写查询提供程序。你知道,我们有linq to sqllinq to xml所以..如果你想要写linq驱动程序的目标您的数据strucutres( linq to your data),所以你的API的用户将有可能运行linq对查询您的数据结构,你必须选择IQueryable
蒂格兰

2
你似乎解释之间的差异IQueryableIEnumerable。我知道区别,那不是我要的。我在问为什么有人要采用实现的东西IEnumerable,并IQueryable使用AsQueryable扩展方法将其转换为。那是您要回答的吗?我仍然无法分辨..
Ocelot20 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.