繁体   English   中英

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

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

以下是两个返回相同数据的查询。 其他风格,我不确定哪个更好。

哪些因素影响这些查询? 使用一种样式相对于另一种样式有什么好处?

样品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 };

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

更新:您已固定标题,因此请忽略该咆哮。

问题的标题与代码示例无关。 您的问题暗示一种语法是IEnumerable,另一种语法是IQueryable,但这是不正确的。 在您的示例中,如果db.Surveys是一个IQueryable,则两个示例都在使用IQueryable。 我将尝试回答两个问题。

您的两个代码示例只是编写相同LINQ查询的不同方法(假设它们编写正确)。 示例1中的代码只是示例2中代码的简写。编译器以相同的方式对待两个示例中的代码。 想想C#编译器对待int? Nullable<System.Int32>相同。 C#和VB.Net语言都提供了这种速记查询语法。 其他语言可能没有这种语法,因此您必须使用示例2语法。 实际上,其他语言甚至可能不支持扩展方法或lambda表达式,因此您必须使用更丑陋的语法。


更新:

进一步以Sander的示例为例,当您编写以下代码(查询理解语法)时:

var surveyNames = from s in db.Surveys select s.Name

认为编译器将这种简化形式(扩展方法和lambda表达式)变成了:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

但是实际上扩展方法和lambda表达式本身就是速记。 编译器发出这样的信息(不完全是,只是给出一个想法):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; };
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector);

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


使用一种样式相对于另一种样式有什么好处?

对于小型查询,扩展方法可以更紧凑:

var items = source.Where(s => s > 5);

同样,扩展方法的语法可以更灵活,例如条件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);

此外,只有扩展方法语法可以使用几种方法(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();

另一方面,当查询变得更大和更复杂时,查询理解语法会更清晰,尤其是当您开始letgroupjoin等复杂化时。

最后,我通常将使用对每个特定查询更有效的方法。


更新:您已固定标题,因此忽略其余部分...

现在,关于您的标题:就LINQ而言,IEnumerable和IQueryable非常相似。 它们都具有几乎相同的扩展方法(选择,位置,计数等),主要区别(仅?)是IEnumerable将Func<TIn,TOut>作为参数,而IQueryable将Expression<Func<TIn,TOut>>作为参数。 Expression<Func<TIn,TOut>>作为参数。 两种表达方式相同(通常是lamba表达式),但在内部,它们是完全不同的。

IEnumerable是LINQ to Objects的门户。 可以在任何IEnumerable(数组,列表,可以用foreach进行迭代的任何对象)上调用LINQ to Objects扩展方法,并且Func<TIn,TOut>在编译时转换为IL,并且在运行时像普通方法代码一样运行。 注意,其他一些LINQ提供程序使用IEnumerable,因此实际上是在后台使用LINQ to Objects(LINQ to XML,LINQ to DataSet)。

LINQ to SQL,LINQ to Entities和其他LINQ提供程序使用IQueryable,它们需要检查查询并将其翻译而不是直接执行代码。 可查询的查询及其Expression<Func<TIn,TOut>>不会在编译时编译到IL中。 而是创建一个表达式树 ,并可以在运行时对其进行检查。 这允许将语句转换为其他查询语言(例如T-SQL)。 表达式树可以在运行时编译为Func <TIn,TOut>并在需要时执行。

这个问题中可以找到一个说明差异的示例,其中OP希望在SQL Server中执行LINQ to SQL查询的一部分,将对象放入托管代码中,并在LINQ to Objects中进行其余的查询。 为此,他要做的就是将IQueryable转换为IEnumerable,他希望在其中进行切换。

LINQ是技术的流行语。

IQueryable是LINQ使用的.NET接口。

除了样式,两者之间没有区别。 使用您喜欢的任何样式。

对于较长的语句,我喜欢第一种样式(如此处所示),对于较短的语句,我喜欢第二种样式。

第一个示例中的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; }
    }

这显然是一个愚蠢的示例,但是请注意,这里有一个Where方法,该方法只返回将stringprop设置为Hello World的新MyClass。 展示:

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

这将导致写出“ Hello World”。 同样,该示例显然毫无意义,但它证明了“ where”语法只是在代码中寻找采用Func的Where方法。

查询表达式和扩展方法是两种完全相同的方法。 查询表达式在编译时会转换为扩展方法-对于对SQL更熟悉的人来说,它们只是语法糖。

当您编写此代码时:

var surveyNames = from s in db.Surveys select s.Name;

编译器将其转换为:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

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

1. /您的问题标题与您的要求不符。
2. /您的问题标题确实没有意义。 Linq代表语言集成查询,是一堆技术和实践的总称,IQueryable是通常用于促进Linq的接口。 您正在比较苹果和橙子
3. /关于您实际的问题,主要区别在于样式,对于像这样的复杂查询,我个人偏爱第二版,因为它清楚地显示了结果集的进度。

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 };

您可以尝试下面的代码来获取书面查询的表达式

var exp=x.Expression;

当查询不太复杂时使用表达式

值得一提的另一点是,Linq扩展方法遵循C#语言,而对查询理解的东西进行了预处理,就像内置在编译器中一样。 即,您可以导航到.Select(x =>的定义,而不from ... where ... select

我认为您的问题最好这样表达:“相对于LINQ,IEnumerable <T>和IQueryable <T>有什么区别”

LINQ查询默认情况下返回IQueryable <T>。 IQueryable <T>允许您在执行查询之前将其他过滤器或“子句”附加到查询中。

您的LINQ查询(第一个示例)和使用方法链接的LINQ(第二个示例)使用相同的语法产生相同的结果。

可以将LINQ查询作为LINQ方法链编写,反之亦然。 这确实取决于您的偏好。

@Lucas:区别在于IEnumerable <T>进行内存中查询,而IQueryable <T>进行内存外查询。 意思是,一旦进入foreach迭代器,您将使用IEnumerable,并且在通过扩展方法或from o in object synatax中使用LINQ from o in object来构建查询时,您将在构建IQueryable <T>。 触摸枚举器后,将立即执行IQueryable <T>。

暂无
暂无

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

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