C# LINQ 查询表达式和扩展方法有什么区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/796246/
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
What is the difference between LINQ query expressions and extension methods
提问by TonyAbell
Below are two queries that return the same data. Other then style I am not sure which is better.
下面是返回相同数据的两个查询。其他风格我不确定哪个更好。
What factors influence these queries? What are the benefits of using one style over the other?
哪些因素会影响这些查询?使用一种样式比另一种样式有什么好处?
Sample 1
示例 1
var x = from s in db.Surveys
join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
join q in db.Questions on sq.Question_ID equals q.ID
join qg in db.Question_Groups on q.ID equals qg.Question_ID
where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
select new { question = sq.Question, status = sq.Status, grp = qg };
Sample 2
样本 2
var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type))
.Join(db.Survey_Questions,
s => s.ID,
sq => sq.Survey_ID,
(s, sq) => new
{
question = sq.Question,
status = sq.Status
})
.Join(db.Question_Groups,
q => q.question.ID,
qg => qg.Question_ID,
(q, qg) => new
{
question = q.question,
status = q.status,
group = qg
}).ToList();
采纳答案by Lucas
Update: You have fixed your title, so ignore the rant.
更新:你已经修正了你的标题,所以忽略咆哮。
The title of your question has nothing to do with your code samples. Your question implies that one syntax is IEnumerable and the other is IQueryable, but this is incorrect. In your samples, if db.Surveys
is an IQueryable, then bothyour samples are using IQueryable. I will try to answer bothquestions.
您的问题标题与您的代码示例无关。您的问题意味着一种语法是 IEnumerable,另一种是 IQueryable,但这是不正确的。在您的示例中,如果db.Surveys
是 IQueryable,则您的两个示例都使用 IQueryable。我将尝试回答这两个问题。
Your two code samples are just different ways of writing the same LINQ queries (assuming they are well-written). The code in sample 1 is just shorthand for the code in sample 2. The compiler treats the code in both samples the same way. Think of the way the C# compiler will treat int?
the same as Nullable<System.Int32>
. Both the C# and VB.Net languages provide this shorthand query syntax. Other languages might not have this syntax and you would have to use the sample 2 syntax. In fact, other languages might not even support extension methods or lambda expressions, and you would have to use an uglier syntax yet.
您的两个代码示例只是编写相同 LINQ 查询的不同方式(假设它们编写得很好)。示例 1 中的代码只是示例 2 中代码的简写。编译器以相同的方式处理两个示例中的代码。想想 C# 编译器将如何处理int?
与Nullable<System.Int32>
. C# 和 VB.Net 语言都提供了这种速记查询语法。其他语言可能没有此语法,您必须使用示例 2 语法。事实上,其他语言甚至可能不支持扩展方法或 lambda 表达式,您将不得不使用更丑陋的语法。
Update:
更新:
To take Sander's example further, when you write this (query comprehension syntax):
进一步看 Sander 的例子,当你写这个(查询理解语法)时:
var surveyNames = from s in db.Surveys select s.Name
You thinkthe compiler turns that shorthand into this (extension methods and lambda expression):
你认为编译器把这个简写变成了这个(扩展方法和 lambda 表达式):
IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);
But actually extension methods and lambda expressions are shorthand themselves. The compilers emits something like this (not exactly, but just to give an idea):
但实际上扩展方法和 lambda 表达式本身就是速记。编译器发出这样的东西(不完全是,只是为了提供一个想法):
Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; };
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector);
Note that Select()
is just a static method in the Queryable
class. If your .NET language did not support query syntax, lambdas, or extension methods, that is kinda how you would have to write the code yourself.
请注意,这Select()
只是类中的静态方法Queryable
。如果您的 .NET 语言不支持查询语法、lambdas 或扩展方法,那么您将不得不自己编写代码。
What are the benefits of using one style over the other?
使用一种样式比另一种样式有什么好处?
For small queries, extension methods can be more compact:
对于小型查询,扩展方法可以更紧凑:
var items = source.Where(s => s > 5);
Also, the extension method syntax can be more flexible, such as conditional where clauses:
此外,扩展方法语法可以更灵活,例如条件 where 子句:
var items = source.Where(s => s > 5);
if(smallerThanThen)
items = items.Where(s => s < 10);
if(even)
items = items.Where(s => (s % 2) == 0);
return items.OrderBy(s => s);
In addition, several methods are only available through extension method syntax (Count(), Aggregate(), Take(), Skip(), ToList(), ToArray(), etc), so if I'll use one of these, I'll usually write the whole query in this syntax to avoid mixing both syntaxes.
此外,有几种方法只能通过扩展方法语法使用(Count()、Aggregate()、Take()、Skip()、ToList()、ToArray() 等),所以如果我将使用其中一种,我通常会用这种语法编写整个查询,以避免混合使用这两种语法。
var floridaCount = source.Count(s => s.State == "FL");
var items = source
.Where(s => s > 5)
.Skip(5)
.Take(3)
.ToList();
On the other hand, when a query gets bigger and more complex, query comprehension syntax can be clearer, especially once you start complicating with a few let
, group
, join
, etc.
在另一方面,当查询变得更大,更复杂,查询综合语法可以更清晰,尤其是当你开始变得复杂一些let
,group
,join
,等。
In the end I will usually use whichever works better for each specific query.
最后,我通常会使用对每个特定查询更有效的方法。
Update: you fixed your title, so ignore the rest...
更新:你修正了你的标题,所以忽略其余的......
Now, about your title: With respect to LINQ, IEnumerable and IQueryable are very similar. They both have pretty much the same extension methods (Select, Where, Count, etc), with the main (only?) difference being that IEnumerable takes Func<TIn,TOut>
as paremeters and IQueryable takes Expression<Func<TIn,TOut>>
as parameters. You express both the same way (usually lamba expressions), but internally they are completely different.
现在,关于您的标题:关于 LINQ,IEnumerable 和 IQueryable 非常相似。它们都有几乎相同的扩展方法(Select、Where、Count 等),主要(唯一?)区别在于 IEnumerableFunc<TIn,TOut>
作为参数,而 IQueryableExpression<Func<TIn,TOut>>
作为参数。您以相同的方式表达(通常是lamba 表达),但在内部它们是完全不同的。
IEnumerable is the doorway to LINQ to Objects. The LINQ to Objects extension methods can be called on any IEnumerable (arrays, lists, anything you can iterate with foreach
) and the Func<TIn,TOut>
is converted to IL at compile time and runs like a normal method code at run time. Note that some other LINQ providers use IEnumerable and so are actually using LINQ to Objects behind the scenes (LINQ to XML, LINQ to DataSet).
IEnumerable 是 LINQ to Objects 的入口。LINQ to Objects 扩展方法可以在任何 IEnumerable(数组、列表、任何可以迭代的对象)上调用,foreach
并且Func<TIn,TOut>
在编译时转换为 IL,并在运行时像普通方法代码一样运行。请注意,其他一些 LINQ 提供程序使用 IEnumerable,因此实际上在幕后使用 LINQ to Objects(LINQ to XML、LINQ to DataSet)。
IQueryable is used by LINQ to SQL, LINQ to Entities, and other LINQ providers which need to examine your query and translate it instead of executing your code directly. IQueryable queries and their Expression<Func<TIn,TOut>>
s are not compiled into IL at compile time. Instead an expression treeis created and can be examined at run time. This allows the statements to be translated into other query languages (for example T-SQL). An expression tree can be compiled into a Func<TIn,TOut> at run time and executed if desired.
IQueryable 由 LINQ to SQL、LINQ to Entities 和其他需要检查您的查询并转换它而不是直接执行您的代码的 LINQ 提供程序使用。IQueryable 查询及其Expression<Func<TIn,TOut>>
s 在编译时不会编译到 IL 中。而是创建了一个表达式树,并可以在运行时进行检查。这允许将语句翻译成其他查询语言(例如 T-SQL)。表达式树可以在运行时编译为 Func<TIn,TOut> 并在需要时执行。
An example that illustrates the difference can be found in this questionwhere the OP wants to do part of a LINQ to SQL query in SQL Server, bring the objects into managed code, and do the rest of the query in LINQ to Objects. To achieve this all he has to do is cast the IQueryable into an IEnumerable where he wants the switch to happen.
在这个问题中可以找到一个说明差异的示例,其中 OP 希望在 SQL Server 中执行部分 LINQ to SQL 查询,将对象引入托管代码,然后在 LINQ to Objects 中执行其余查询。为了实现这一点,他所要做的就是将 IQueryable 转换为他希望发生切换的 IEnumerable。
回答by James Curran
LINQ is buzz word for a technology.
LINQ 是一种技术的流行词。
IQueryable is a .NET Interface which is used by LINQ.
IQueryable 是 LINQ 使用的 .NET 接口。
Other than the style, there is no difference between the two. Use whichever style you prefer.
除了风格,两者没有任何区别。使用您喜欢的任何样式。
I prefer the first style for long statement (like that one shown here) and the second for very short statements.
对于长语句,我更喜欢第一种样式(就像这里显示的那种),而对于非常短的语句,我更喜欢第二种样式。
回答by Chris
I think your question is better phrased like this, "What is the difference between IEnumerable<T> and IQueryable<T> with respect to LINQ"
我认为你的问题用这样的措辞更好,“IEnumerable<T> 和 IQueryable<T> 与 LINQ 有什么区别”
LINQ queries return an IQueryable<T> by default. IQueryable<T> allows you to append other filters or "clauses" onto your query before you execute it.
LINQ 查询默认返回 IQueryable<T>。IQueryable<T> 允许您在执行之前将其他过滤器或“子句”附加到您的查询中。
Your LINQ query (first example) and your LINQ using method chaining (second example) produce the same result, with different syntax.
您的 LINQ 查询(第一个示例)和使用方法链的 LINQ(第二个示例)产生相同的结果,但语法不同。
It is possible to write a LINQ query as a LINQ method chain and visa versa. It really depends on your preference.
可以将 LINQ 查询编写为 LINQ 方法链,反之亦然。这真的取决于你的喜好。
@Lucas: The different is IEnumerable<T> does in-memory querying and IQueryable<T> does out-of-memory. Meaning, once you are in a foreach
iterator, you are using IEnumerable, and when you are building your query, via either extension methods or using LINQ from o in object
synatax, you are building an IQueryable<T>. The IQueryable<T> is executed as soon as you touch the Enumerator.
@Lucas:不同的是 IEnumerable<T> 进行内存中查询,而 IQueryable<T> 进行内存不足查询。意思是,一旦您进入foreach
迭代器,您就在使用 IEnumerable,而当您通过扩展方法或使用 LINQfrom o in object
语法构建查询时,您正在构建一个 IQueryable<T>。IQueryable<T> 在您触摸 Enumerator 时立即执行。
回答by Tim Jarvis
1./ Your question title does not match what you asked.
2./ Your question title does not really make sense. Linq stands for Language Integrated Query and is an umbrella term for a bunch of technologies and practices, IQueryable is an interface that is commonly used to facilitate Linq. you are comparing Apples and Oranges
3./ About your actual question, the main difference is style, for complex queries like this one, my personal preference is the 2nd version, as it clearly shows the progression of the result sets.
1./您的问题标题与您提出的问题不符。
2./你的问题标题没有意义。Linq 代表语言集成查询,是一系列技术和实践的总称,IQueryable 是一个通常用于促进 Linq 的接口。您正在比较 Apples 和 Oranges
3./ 关于您的实际问题,主要区别在于样式,对于像这样的复杂查询,我个人的偏好是第二个版本,因为它清楚地显示了结果集的进展。
回答by BFree
The where clause in the first example is actually just syntactic sugar for the Where clause in your second method. In fact, you can write your own class that has nothing to do with Linq or IQueryable and just by having a Where method, you can use that syntactic sugar. For example:
第一个示例中的 where 子句实际上只是第二种方法中 Where 子句的语法糖。事实上,您可以编写自己的与 Linq 或 IQueryable 无关的类,只需拥有 Where 方法,您就可以使用该语法糖。例如:
public class MyClass
{
public MyClass Where<T>(Func<MyClass, T> predicate)
{
return new MyClass { StringProp = "Hello World" };
}
public MyClass Select<T>(Func<MyClass, T> predicate)
{
return new MyClass ();
}
public string StringProp { get; set; }
}
This is obviously a stupid example, but note that there's a Where method that just returns a new MyClass with stringprop set to Hello World. To demonstrate:
这显然是一个愚蠢的例子,但请注意,有一个 Where 方法只返回一个新的 MyClass,并将 stringprop 设置为 Hello World。展示:
MyClass a = new MyClass();
var q = from p in a
where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate
select p;
Console.WriteLine(q.StringProp);
This will result in writing out "Hello World". Again, this example is obviously pointless, but it proves the point that the "where" syntax just looks for a Where method in your code that takes a Func.
这将导致写出“Hello World”。同样,这个例子显然毫无意义,但它证明了“where”语法只是在你的代码中寻找一个接受 Func 的 Where 方法的观点。
回答by Sander
Query expressions and extension methods are two ways to do the exact same thing. Query expressions get transformed to extension methods when compiling - they are just syntactic sugar for people who are more comfortable with SQL.
查询表达式和扩展方法是两种完全相同的方法。查询表达式在编译时会转换为扩展方法——对于更熟悉 SQL 的人来说,它们只是语法糖。
When you write this:
当你写这个:
var surveyNames = from s in db.Surveys select s.Name;
The compiler transforms this into:
编译器将其转换为:
IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);
Really, I think query expressions were just created for marketing reasons - a SQL-like language construct to act as an eye-catcher when LINQ was developed, not something that offers much actual use. I find that most people just use the extension methods directly, as they result in a more unified coding style, instead of a mix of C# and SQL.
真的,我认为查询表达式只是出于营销原因而创建的 - 一种类似 SQL 的语言结构,在 LINQ 开发时充当引人注目的对象,而不是提供很多实际用途的东西。我发现大多数人只是直接使用扩展方法,因为它们会产生更统一的编码风格,而不是 C# 和 SQL 的混合。
回答by Prashant Cholachagudda
Your Sample1is top level representation of Linq, it is more readable, and while compiling it'll converted to expression tree i.e your Sample2.
您的Sample1是 Linq 的顶级表示,它更具可读性,并且在编译时将转换为表达式树,即您的Sample2。
var x = from s in db.Surveys
join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
join q in db.Questions on sq.Question_ID equals q.ID
join qg in db.Question_Groups on q.ID equals qg.Question_ID
where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
select new { question = sq.Question, status = sq.Status, grp = qg };
you can try below code to get expression for written query
您可以尝试以下代码来获取书面查询的表达式
var exp=x.Expression;
Expressions are used when query less complicated
查询不太复杂时使用表达式
回答by Justin
Another point worth mentioning is that the Linq extension methods adhere to C# language whereas the query comprehension stuff is preprocessed like is built into the compiler.
i.e you can navigate to the definition of .Select(x =>
whereas you cannot for from ... where ... select
值得一提的另一点是,Linq 扩展方法遵循 C# 语言,而查询理解的内容是预处理的,就像编译器内置的一样。即你可以导航到 .Select(x => 的定义,而你不能from ... where ... select