简体   繁体   English

LINQ查询表达式和扩展方法有什么区别

[英]What is the difference between LINQ query expressions and extension methods

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();

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. 您的问题暗示一种语法是IEnumerable,另一种语法是IQueryable,但这是不正确的。 In your samples, if db.Surveys is an IQueryable, then both your samples are using IQueryable. 在您的示例中,如果db.Surveys是一个IQueryable,则两个示例都在使用IQueryable。 I will try to answer both questions. 我将尝试回答两个问题。

Your two code samples are just different ways of writing the same LINQ queries (assuming they are well-written). 您的两个代码示例只是编写相同LINQ查询的不同方法(假设它们编写正确)。 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. 示例1中的代码只是示例2中代码的简写。编译器以相同的方式对待两个示例中的代码。 Think of the way the C# compiler will treat int? 想想C#编译器对待int? the same as Nullable<System.Int32> . Nullable<System.Int32>相同。 Both the C# and VB.Net languages provide this shorthand query syntax. C#和VB.Net语言都提供了这种速记查询语法。 Other languages might not have this syntax and you would have to use the sample 2 syntax. 其他语言可能没有这种语法,因此您必须使用示例2语法。 In fact, other languages might not even support extension methods or lambda expressions, and you would have to use an uglier syntax yet. 实际上,其他语言甚至可能不支持扩展方法或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 think the 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. 但是实际上扩展方法和lambda表达式本身就是速记。 The compilers emits something like this (not exactly, but just to give an idea): 编译器发出这样的信息(不完全是,只是给出一个想法):

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. 请注意, Select()只是Queryable类中的静态方法。 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. 如果您的.NET语言不支持查询语法,lambda或扩展方法,那就是您必须自己编写代码的方式。


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. 另一方面,当查询变得更大和更复杂时,查询理解语法会更清晰,尤其是当您开始letgroupjoin等复杂化时。

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. 现在,关于您的标题:就LINQ而言,IEnumerable和IQueryable非常相似。 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. 它们都具有几乎相同的扩展方法(选择,位置,计数等),主要区别(仅?)是IEnumerable将Func<TIn,TOut>作为参数,而IQueryable将Expression<Func<TIn,TOut>>作为参数。 Expression<Func<TIn,TOut>>作为参数。 You express both the same way (usually lamba expressions), but internally they are completely different. 两种表达方式相同(通常是lamba表达式),但在内部,它们是完全不同的。

IEnumerable is the doorway to LINQ to Objects. IEnumerable是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. 可以在任何IEnumerable(数组,列表,可以用foreach进行迭代的任何对象)上调用LINQ to Objects扩展方法,并且Func<TIn,TOut>在编译时转换为IL,并且在运行时像普通方法代码一样运行。 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). 注意,其他一些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. LINQ to SQL,LINQ to Entities和其他LINQ提供程序使用IQueryable,它们需要检查查询并将其翻译而不是直接执行代码。 IQueryable queries and their Expression<Func<TIn,TOut>> s are not compiled into IL at compile time. 可查询的查询及其Expression<Func<TIn,TOut>>不会在编译时编译到IL中。 Instead an expression tree is created and can be examined at run time. 而是创建一个表达式树 ,并可以在运行时对其进行检查。 This allows the statements to be translated into other query languages (for example T-SQL). 这允许将语句转换为其他查询语言(例如T-SQL)。 An expression tree can be compiled into a Func<TIn,TOut> at run time and executed if desired. 表达式树可以在运行时编译为Func <TIn,TOut>并在需要时执行。

An example that illustrates the difference can be found in this question where 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. 这个问题中可以找到一个说明差异的示例,其中OP希望在SQL Server中执行LINQ to SQL查询的一部分,将对象放入托管代码中,并在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. 为此,他要做的就是将IQueryable转换为IEnumerable,他希望在其中进行切换。

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. 对于较长的语句,我喜欢第一种样式(如此处所示),对于较短的语句,我喜欢第二种样式。

The where clause in the first example is actually just syntactic sugar for the Where clause in your second method. 第一个示例中的where子句实际上只是第二个方法中where子句的语法糖。 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. 实际上,您可以编写自己的与Linq或IQueryable无关的类,仅通过使用Where方法,就可以使用该语法糖。 For example: 例如:

    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. 这显然是一个愚蠢的示例,但是请注意,这里有一个Where方法,该方法只返回将stringprop设置为Hello World的新MyClass。 To demonstrate: 展示:

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". 这将导致写出“ 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. 同样,该示例显然毫无意义,但它证明了“ where”语法只是在代码中寻找采用Func的Where方法。

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. 确实,我认为查询表达式是出于市场营销的原因而创建的-一种类似SQL的语言构造,在开发LINQ时引人注目,而实际使用情况并不多。 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. 我发现大多数人只是直接使用扩展方法,因为它们导致更统一的编码样式,而不是C#和SQL的混合。

1./ Your question title does not match what you asked. 1. /您的问题标题与您的要求不符。
2./ Your question title does not really make sense. 2. /您的问题标题确实没有意义。 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. Linq代表语言集成查询,是一堆技术和实践的总称,IQueryable是通常用于促进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. 3. /关于您实际的问题,主要区别在于样式,对于像这样的复杂查询,我个人偏爱第二版,因为它清楚地显示了结果集的进度。

Your Sample1 is top level representation of Linq, it is more readable, and while compiling it'll converted to expression tree ie 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 当查询不太复杂时使用表达式

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. 值得一提的另一点是,Linq扩展方法遵循C#语言,而对查询理解的东西进行了预处理,就像内置在编译器中一样。 ie you can navigate to the definition of .Select(x => whereas you cannot for from ... where ... select 即,您可以导航到.Select(x =>的定义,而不from ... where ... select

I think your question is better phrased like this, "What is the difference between IEnumerable<T> and IQueryable<T> with respect to LINQ" 我认为您的问题最好这样表达:“相对于LINQ,IEnumerable <T>和IQueryable <T>有什么区别”

LINQ queries return an IQueryable<T> by default. LINQ查询默认情况下返回IQueryable <T>。 IQueryable<T> allows you to append other filters or "clauses" onto your query before you execute it. 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. 可以将LINQ查询作为LINQ方法链编写,反之亦然。 It really depends on your preference. 这确实取决于您的偏好。

@Lucas: The different is IEnumerable<T> does in-memory querying and IQueryable<T> does out-of-memory. @Lucas:区别在于IEnumerable <T>进行内存中查询,而IQueryable <T>进行内存外查询。 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>. 意思是,一旦进入foreach迭代器,您将使用IEnumerable,并且在通过扩展方法或from o in object synatax中使用LINQ from o in object来构建查询时,您将在构建IQueryable <T>。 The IQueryable<T> is executed as soon as you touch the Enumerator. 触摸枚举器后,将立即执行IQueryable <T>。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM