C# 为什么使用 .AsEnumerable() 而不是强制转换为 IEnumerable<T>?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2013846/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why use .AsEnumerable() rather than casting to IEnumerable<T>?
提问by Erik Forbes
One of the extension methods on IEnumerable<T>
is .AsEnumerable()
. This method converts the enumerable object it was called on into an instance of IEnumerable<T>
. However, since an object must implement IEnumerable<T>
in order to apply to this extension method, converting to IEnumerable<T>
is a simple matter of casting to IEnumerable<T>
. My question is why does this method exist at all?
上的扩展方法之一IEnumerable<T>
是.AsEnumerable()
. 此方法将调用它的可枚举对象转换为 的实例IEnumerable<T>
。但是,由于对象必须实现IEnumerable<T>
才能应用于此扩展方法,因此转换为IEnumerable<T>
只是简单的转换为IEnumerable<T>
。我的问题是为什么这种方法存在?
Example:
例子:
List<string> strings = new List<string>() { "test", "test2", "test3" };
IEnumerable<string> stringsEnum1 = strings.AsEnumerable();
IEnumerable<string> stringsEnum2 = (IEnumerable<string>)strings;
In the example above, stringsEnum1
and stringsEnum2
are equivalent. What's the point of the extension method?
在上面的例子中,stringsEnum1
和stringsEnum2
是等价的。扩展方法的重点是什么?
Edit: As a corollary, why is there an .AsQueryable()
method when casting to IQueryable<T>
is equivalent?
编辑:作为推论,为什么.AsQueryable()
在转换IQueryable<T>
为等效时有一种方法?
采纳答案by jason
Readability is the main issue here. Consider that
可读性是这里的主要问题。考虑一下
Table.AsEnumerable().Where(somePredicate)
is far more readable than
可读性比
((IEnumerable<TableObject>)Table).Where(somePredicate).
Or imagine wanting to execute part of the query on the SQL Server and the rest in memory:
或者想象一下要在 SQL Server 上执行部分查询,而在内存中执行其余部分:
Table.Where(somePredicate)
.Select(someProjection)
.AsEnumerable()
.SomethingElse()
versus
相对
((IEnumerable<SomeProjectionType>)Table.Where(somePredicate)
.Select(someProjection))
.SomethingElse()
Now, as for why such a method is useful at all think of the example of a Table
in a LINQ to SQL DataContext
. As Table
is an IQueryable
it implements IEnumerable
. When you invoke a Where
method on such a Table
and enumerate through the results, code is executed that eventually causes a SQL statement to be executed on a SQL Server. What AsEnumerable
does is says, no, I don't want to use the LINQ to SQL provider to execute the Where
, I want to use the LINQ to Objects implementation of Where
.
现在,至于为什么这样的方法有用,请考虑Table
LINQ to SQL 中的 a示例DataContext
。由于Table
是IQueryable
它实现IEnumerable
。当您Where
在此类上调用方法Table
并枚举结果时,将执行最终导致 SQL 语句在 SQL Server 上执行的代码。什么AsEnumerable
是说,不,我不想使用 LINQ to SQL 提供程序来执行Where
,我想使用Where
.
Thus enumerating over
因此枚举
Table.Where(somePredicate)
causes a query to be executed on a SQL Server whereas enumerating over
导致在 SQL Server 上执行查询,同时枚举
Table.AsEnumerable().Where(somePredicate)
brings the table represented by Table
into memory and executes the Where
functionality in memory (and not on the SQL Server!)
将 表示的表Table
带入内存并Where
在内存中执行功能(而不是在 SQL Server 上!)
This is the point of AsEnumerable
: to allow you to hide a specific implementation of IEnumerable
methods and instead use the standard implementation.
这就是AsEnumerable
:允许您隐藏IEnumerable
方法的特定实现,而是使用标准实现。
回答by Meta-Knight
It's just a nicest and shortest way to cast to an IEnumerable. If you look at it in Reflector, you can see it does nothing except return the object as an IEnumerable.
这只是转换为 IEnumerable 的最好和最短的方法。如果您在 Reflector 中查看它,您会发现它除了将对象作为 IEnumerable 返回之外什么都不做。
From MSDN:
来自 MSDN:
The AsEnumerable(Of TSource)(IEnumerable(Of TSource)) method has no effect other than to change the compile-time type of source from a type that implements IEnumerable(Of T) to IEnumerable(Of T) itself.
除了将源的编译时类型从实现 IEnumerable(Of T) 的类型更改为 IEnumerable(Of T) 本身之外,AsEnumerable(Of TSource)(IEnumerable(Of TSource)) 方法没有任何作用。
回答by LukeH
As you say, if a type already implements IEnumerable<T>
then there's not really any functional difference between casting to the interface or calling the AsEnumerable
method.
正如你所说,如果一个类型已经实现,IEnumerable<T>
那么在转换到接口或调用AsEnumerable
方法之间没有任何功能上的区别。
My guess, and it's only a guess, is that calling AsEnumerable
improves readability and retains the fluent signature of other LINQ extension methods:
我的猜测(也只是猜测)是调用AsEnumerable
提高了可读性并保留了其他 LINQ 扩展方法的流畅签名:
var query = ((IEnumerable<YourType>)yourCollection).Select(x => x.YourProperty);
// vs
var query = yourCollection.AsEnumerable().Select(x => x.YourProperty);
It also allows types that don't implement IEnumerable<T>
- for example, DataTable
- to have their own version of the AsEnumerable
extension. This allows you to continue using the same patternin queries against those types - even though it's a different AsEnumerable
method that you're calling - without needing to worry about whether or not the type really implements IEnumerable<T>
.
它还允许未实现的类型IEnumerable<T>
-例如DataTable
- 拥有自己的AsEnumerable
扩展版本。这允许您在针对这些类型的查询中继续使用相同的模式- 即使它AsEnumerable
是您正在调用的不同方法 - 无需担心该类型是否真的实现IEnumerable<T>
.
回答by Erik Forbes
I've thought of a reason apart from readability, though related to query implementation: using Linq to Objects on anonymous types returned via another Linq provider. You can't cast to an anonymous type (or a collection of anonymous types), but you can use .AsEnumerable()
to perform the cast for you.
除了可读性之外,我还想到了一个原因,尽管与查询实现有关:在通过另一个 Linq 提供程序返回的匿名类型上使用 Linq to Objects。您不能转换为匿名类型(或匿名类型的集合),但您可以使用.AsEnumerable()
它为您执行转换。
Example:
例子:
// Get an IQueryable of anonymous types.
var query = from p in db.PeopleTable /* Assume Linq to SQL */
select new { Name = p.Name, Age = p.Age };
// Execute the query and pull the results into an IEnumerable of anonymous types
var @enum = query.AsEnumerable();
// Use Linq to Objects methods to further refine.
var refined = from p in @enum
select new
{
Name = GetPrettyName(p.Name),
DOB = CalculateDOB(p.Age, DateTime.Now)
};
Clearly the reason here is that we want to use something like Linq to SQL to pull down some records into an anonymous type, then perform some custom logic (that wouldn't be possible via Linq to SQL) using Linq to Objects on the client-side.
很明显,这里的原因是我们想要使用类似 Linq to SQL 的东西将一些记录下拉到一个匿名类型中,然后在客户端使用 Linq to Objects 执行一些自定义逻辑(通过 Linq to SQL 是不可能的) -边。
Casting to IEnumerable<_anon>
isn't possible, so .AsEnumerable()
is the only way to go.
投射到IEnumerable<_anon>
是不可能的,所以.AsEnumerable()
是唯一的出路。
Thanks everyone who answered to help me piece this together. =)
感谢所有回答帮助我拼凑的人。=)
回答by james
Anonymous types are a main reason to provide these kinds of extension methods. (you cannot use anonymous types in generics parameters) But a method call can use type inference allowing you to omit specifying the type in the generic parameters.
匿名类型是提供这些扩展方法的主要原因。(您不能在泛型参数中使用匿名类型)但是方法调用可以使用类型推断,允许您省略在泛型参数中指定类型。
回答by Richard Petheram
If there is a method on an object that has the same name as a Linq extension method it hides the extension method. Using AsEnumerable allows you to get at the extension.
如果对象上有一个与 Linq 扩展方法同名的方法,它会隐藏扩展方法。使用 AsEnumerable 可以让您获得扩展。
This appears to be new in SP1.
这在 SP1 中似乎是新的。
Yesterday I had a line of code that extracted member identifiers from a data table:-
昨天我有一行代码从数据表中提取成员标识符:-
var lMmIds = new List<int>(
lDmMember.DataTable.Select(R => R.MmId)
);
which worked just fine until I installed SP1. Now it won't work unless it reads
在我安装 SP1 之前它工作得很好。现在它不会工作,除非它读取
var lMmIds = new List<int>(
lDmMember.DataTable.AsEnumerable().Select(R => (int)((dsMtables.tbMMemberRow)R).MmId)
);
Edit: I found the real reason
编辑:我找到了真正的原因
It's so that you can use both remote methods (e.g. WHERE in a SQL statement) and local methods in the same linq statement. Without using AsEnumerable (i.e. just casting) it will make the query generator attempt to create an expression tree for remote execution that contains the local method. Putting AsEnumerable into the query will cause the rest of that query to be executed locally on the results of the remote query.
这样您就可以在同一个 linq 语句中同时使用远程方法(例如 SQL 语句中的 WHERE)和本地方法。如果不使用 AsEnumerable(即只是强制转换),它将使查询生成器尝试为包含本地方法的远程执行创建表达式树。将 AsEnumerable 放入查询将导致该查询的其余部分在远程查询的结果上本地执行。
From https://msdn.microsoft.com/en-us/library/bb335435(v=vs.110).aspx
来自https://msdn.microsoft.com/en-us/library/bb335435(v=vs.110).aspx
A Table type that represents a database table could have a Where method that takes the predicate argument as an expression tree and converts the tree to SQL for remote execution. If remote execution is not desired, for example because the predicate invokes a local method, the AsEnumerable method can be used to hide the custom methods and instead make the standard query operators available.
表示数据库表的 Table 类型可以有一个 Where 方法,该方法将谓词参数作为表达式树并将该树转换为 SQL 以供远程执行。如果不需要远程执行,例如因为谓词调用本地方法,则可以使用 AsEnumerable 方法来隐藏自定义方法,而是使标准查询运算符可用。
回答by Timeless
As I'm reading the book C# 6.0 in a Nutshell
. Below is an example of AsEnumerable
in the book.
当我在看书的时候C# 6.0 in a Nutshell
。下面是AsEnumerable
书中的一个例子。
The purpose is to cast an IQueryable<T>
sequence to IEnumerable<T>
, forcing subsequent query operators to bind to Enumerable operators instead of Queryable operators. This causes the remainder of the query to execute locally.
目的是将IQueryable<T>
序列转换为IEnumerable<T>
,强制后续查询运算符绑定到 Enumerable 运算符而不是 Queryable 运算符。这会导致查询的其余部分在本地执行。
To illustrate, suppose we had a MedicalArticles
table in SQL Server and wanted to use LINQ to SQL or EF to retrieve all articles on influenza whose abstract contained less than 100 words. For the latter predicate, we need a regular expression:
为了说明这一点,假设我们MedicalArticles
在 SQL Server 中有一个表,并且想要使用 LINQ to SQL 或 EF 来检索摘要包含少于 100 个单词的所有关于流感的文章。对于后一个谓词,我们需要一个正则表达式:
Regex wordCounter = new Regex (@"\b(\w|[-'])+\b");
var query = dataContext.MedicalArticles
.Where (article => article.Topic == "influenza" &&
wordCounter.Matches (article.Abstract).Count < 100);
The problem is that SQL Server doesn't support regular expressions, so the LINQ-to-db providers will throw an exception, complaining that the query cannot be translated to SQL. We can solve this by querying in two steps: first retrieving all articles on influenza through a LINQ to SQL query, and then filtering locally for abstracts of less than 100 words:
问题在于 SQL Server 不支持正则表达式,因此 LINQ-to-db 提供程序会抛出异常,抱怨无法将查询转换为 SQL。我们可以通过分两步查询来解决这个问题:首先通过 LINQ to SQL 查询检索所有关于流感的文章,然后在本地过滤少于 100 字的摘要:
Regex wordCounter = new Regex (@"\b(\w|[-'])+\b");
IEnumerable<MedicalArticle> sqlQuery = dataContext.MedicalArticles
.Where (article => article.Topic == "influenza");
IEnumerable<MedicalArticle> localQuery = sqlQuery
.Where (article => wordCounter.Matches (article.Abstract).Count < 100);
With AsEnumerable, we can do the same in a single query:
使用 AsEnumerable,我们可以在单个查询中执行相同的操作:
var query = dataContext.MedicalArticles
.Where (article => article.Topic == "influenza")
.AsEnumerable()
.Where (article => wordCounter.Matches (article.Abstract).Count < 100);
An alternative to calling AsEnumerable is to call ToArray or ToList. The advantage of AsEnumerable is that it doesn't force immediate query execution, nor does it create any storage structure.
调用 AsEnumerable 的另一种方法是调用 ToArray 或 ToList。AsEnumerable 的优点是它不会强制立即执行查询,也不会创建任何存储结构。