首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >.ToList()、.AsEnumerable()、AsQueryable()之间有什么区别?

.ToList()、.AsEnumerable()、AsQueryable()之间有什么区别?
EN

Stack Overflow用户
提问于 2018-03-26 07:14:57
回答 2查看 0关注 0票数 0

我知道LINQ到实体和LINQto对象的一些不同之处,这是第一个实现的。IQueryable和第二个工具IEnumerable我的问题范围在EF 5之内。

我的问题是,这三种方法的技术区别是什么?如.ToList().AsQueryable()

  1. 这些方法到底意味着什么?
  2. 是否有任何性能问题或某些东西会导致使用一个而另一个?
  3. 为什么一个人会使用,例如,.ToList().AsQueryable()而不是.AsQueryable()?
EN

Stack Overflow用户

发布于 2018-03-26 15:40:35

集中讨论AsEnumerableAsQueryable提到ToList():

这些方法是做什么的?

AsEnumerableAsQueryable铸造或转换为IEnumerableIQueryable分别。

  • 当源对象已经实现目标接口时,源对象本身将被返回,但是铸造到目标界面。换句话说:类型没有改变,但是编译时类型是。
  • 当源对象未实现目标接口时,源对象为转换转换为实现目标接口的对象。因此,类型和编译时类型都会更改。

让我举几个例子来说明这一点。

代码语言:txt
复制
void ReportTypeProperties<T>(T obj)
{
    Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
    Console.WriteLine("Actual type: {0}", obj.GetType().Name);
}

让我们尝试一个任意的Linq到SQLTable<T>,实现IQueryable:

代码语言:txt
复制
ReportTypeProperties(context.Observations);
ReportTypeProperties(context.Observations.AsEnumerable());
ReportTypeProperties(context.Observations.AsQueryable());

结果:

代码语言:txt
复制
Compile-time type: Table`1
Actual type: Table`1

Compile-time type: IEnumerable`1
Actual type: Table`1

Compile-time type: IQueryable`1
Actual type: Table`1

可以看到表类本身总是被返回,但是它的表示形式会改变。

现在是实现IEnumerable,不是IQueryable:

代码语言:txt
复制
var ints = new[] { 1, 2 };
ReportTypeProperties(ints);
ReportTypeProperties(ints.AsEnumerable());
ReportTypeProperties(ints.AsQueryable());

结果:

代码语言:txt
复制
Compile-time type: Int32[]
Actual type: Int32[]

Compile-time type: IEnumerable`1
Actual type: Int32[]

Compile-time type: IQueryable`1
Actual type: EnumerableQuery`1

AsQueryable()将数组转换为EnumerableQuery,它“表示IEnumerable<T>集合为IQueryable<T>数据源。“。(MSDN)

有什么用?

AsEnumerable经常用于从任何IQueryable实现LINQtoObjects(L2O),主要是因为前者不支持L2O所具有的函数。

例如,在实体框架查询中,我们只能使用有限数量的方法。因此,例如,如果我们需要在查询中使用自己的方法之一,我们通常会编写如下

代码语言:txt
复制
var query = context.Observations.Select(o => o.Id)
                   .AsEnumerable().Select(x => MySuperSmartMethod(x))

ToList-转换IEnumerable<T>转到List<T>-也经常用于这一目的。使用优势AsEnumerablev.V.ToList那是AsEnumerable不执行查询。AsEnumerable保留延迟执行,并且不构建通常无用的中间列表。

另一方面,当需要强制执行LINQ查询时,ToList也能做到这一点。

AsQueryable可用于使LINQ语句中的可枚举集合接受表达式。

注意事项!

AsEnumerable就像毒品一样。这是一个快速的解决方法,但需要付出代价,而且不能解决根本的问题。

在许多堆栈溢出的答案中,我看到人们正在申请AsEnumerable若要解决LINQ表达式中不支持的方法的任何问题,请执行以下操作。但价格并不总是明确的。例如,如果这样做:

代码语言:txt
复制
context.MyLongWideTable // A table with many records and columns
       .Where(x => x.Type == "type")
       .Select(x => new { x.Name, x.CreateDate })

.所有东西都被巧妙地转换成SQL语句滤光片(Where)和项目(Select)。也就是说,SQL结果集的长度和宽度都会减少。

真正的解决办法是:

代码语言:txt
复制
context.MyLongWideTable
       .Where(x => x.Type == "type")
       .Select(x => new { x.Name, DbFunctions.TruncateTime(x.CreateDate) })

这些方法没有做什么?

现在有个重要的警告。当你做的时候

代码语言:txt
复制
context.Observations.AsEnumerable()
                    .AsQueryable()

您将最终得到表示为IQueryable...。(因为这两种方法只转换而不转换)。

但当你这么做的时候

代码语言:txt
复制
context.Observations.AsEnumerable().Select(x => x)
                    .AsQueryable()

结果如何?

Select产生一个WhereSelectEnumerableIterator...。这是一个内部.net类,它实现IEnumerableIQueryable...。因此,转换到另一种类型已经发生,并且随后的AsQueryable再也不能返回原始源了。

这意味着使用AsQueryable无法神奇地注入查询提供程序将它的特定特性变成可枚举的。假设你知道

代码语言:txt
复制
var query = context.Observations.Select(o => o.Id)
                   .AsEnumerable().Select(x => x.ToString())
                   .AsQueryable()
                   .Where(...)

WHERE条件将永远不会转换为SQL。AsEnumerable()然后是LINQ语句,明确地切断了与实体框架查询提供程序的连接。

我故意展示这个例子,因为我在这里看到了一些问题,比如人们试图“注入”Include通过调用AsQueryable。它编译和运行,但是它什么也不做,因为基础对象没有Include实现不再。

票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100003219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档