关于c#:LINQ查询表达式和扩展方法之间有什么区别

What is the difference between LINQ query expressions and extension methods

下面是返回相同数据的两个查询。我不知道哪种款式更好。

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

样品1

1
2
3
4
5
6
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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是可查询的,那么您的两个样本都使用可查询的。我会尽力回答这两个问题。好的。

您的两个代码示例只是编写相同LINQ查询的不同方法(假设它们编写得很好)。示例1中的代码只是示例2中代码的简写。编译器对两个示例中的代码的处理方式相同。想想C编译器对待int?Nullable的方式。C和VB.NET语言都提供了这种简短的查询语法。其他语言可能没有这种语法,您必须使用示例2语法。事实上,其他语言甚至可能不支持扩展方法或lambda表达式,您还必须使用更糟糕的语法。好的。

更新:好的。

为了进一步了解Sander的例子,当您编写这个(查询理解语法)时:好的。

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

您认为编译器会将该速记转换为以下内容(扩展方法和lambda表达式):好的。

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

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

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

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

What are the benefits of using one style over the other?

Ok.

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

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

此外,扩展方法语法可以更灵活,例如条件WHERE子句:好的。

1
2
3
4
5
6
7
8
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()等)来使用,所以如果我要使用其中一种方法,我通常会用这种语法编写整个查询,以避免混淆这两种语法。好的。

1
2
3
4
5
6
7
var floridaCount = source.Count(s => s.State =="FL");

var items = source
            .Where(s => s > 5)
            .Skip(5)
            .Take(3)
            .ToList();

另一方面,当一个查询变得越来越大、越来越复杂时,查询理解语法会更清晰,特别是当您开始使用一些letgroupjoin等使其复杂化时。好的。

最后,对于每个特定的查询,我通常使用哪个更好。好的。

更新:你修改了标题,所以忽略其余的…好的。

现在,关于您的标题:关于LINQ,IEnumerable和iqueryable非常相似。它们都有几乎相同的扩展方法(select、where、count等),其中main(仅适用于?)区别在于,IEnumerable以Func作为参数,iqueryable以Expression>作为参数。两种表达方式都相同(通常是lamba表达式),但在内部它们完全不同。好的。

IEnumerable是Linq到对象的入口。可以在任何IEnumerable(数组、列表、可以与foreach迭代的任何内容)上调用linq to objects扩展方法,并且Func在编译时转换为il,并在运行时像正常方法代码一样运行。请注意,其他一些LINQ提供程序使用IEnumerable,因此实际使用的是Linq to对象(Linq to XML,Linq to DataSet)。好的。

IQueryable由Linq to SQL、Linq to Entities和其他Linq提供程序使用,这些提供程序需要检查并翻译查询,而不是直接执行代码。IQueryable查询及其Expression>在编译时不编译成IL。而是创建一个表达式树,并可以在运行时进行检查。这允许将语句转换为其他查询语言(例如T-SQL)。表达式树可以在运行时编译为func并在需要时执行。好的。

在这个问题中可以找到一个示例,说明了这一区别,其中操作人员希望在SQL Server中执行部分LINQ to SQL查询,将对象引入托管代码,并在LINQ to对象中执行其余查询。为了实现这一点,他所要做的就是将iqueryable强制转换成一个IEnumerable,在那里他希望转换发生。好的。好啊。


Linq是技术的流行语。

IQueryable是Linq使用的.NET接口。

除了风格,两者没有区别。使用你喜欢的风格。

我喜欢长句的第一种风格(如这里所示),而短句的第二种风格。


查询表达式和扩展方法是执行完全相同操作的两种方法。在编译时,查询表达式被转换为扩展方法——对于那些更熟悉SQL的人来说,它们只是语法上的糖分。

当你写这封信时:

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

编译器将其转换为:

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

实际上,我认为查询表达式的创建只是出于市场营销的原因——一种类似SQL的语言构造,在开发Linq时起到吸引眼球的作用,而不是提供大量实际使用的功能。我发现大多数人只是直接使用扩展方法,因为它们会导致更统一的编码风格,而不是混合使用C和SQL。


第一个例子中的WHERE子句实际上只是第二个方法中WHERE子句的语法结构。事实上,您可以编写自己的类,它与Linq或IQueryable无关,您只需使用一个where方法,就可以使用这种语法糖分。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    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方法,它只返回一个新的myClass,其中StringProp设置为hello world。演示:

1
2
3
4
5
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);

这将导致写出"你好世界"。同样,这个例子显然是毫无意义的,但是它证明了"where"语法只在代码中寻找一个接受func的where方法。


您的sample1是linq的顶级表示,它更具可读性,编译时将转换为表达式树,即sample2。

1
2
3
4
5
6
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 };

您可以尝试在下面的代码中获取用于书面查询的表达式

1
var exp=x.Expression;

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


1./您的问题标题与您的要求不匹配。2./你的问题标题没有真正意义。Linq代表语言集成查询,是一个伞形术语,用于各种技术和实践,iQueryable是一个常用于促进Linq的接口。你在比较苹果和桔子3./关于您的实际问题,主要的区别是样式,对于像这样的复杂查询,我个人的偏好是第二个版本,因为它清楚地显示了结果集的进度。


另一点值得一提的是,LINQ扩展方法坚持使用C语言,而查询理解功能是预处理的,就像编译程序中内置的一样。也就是说,您可以导航到的定义。选择(x=>但是你不能为from ... where ... select


我认为你的问题用这样的措辞比较好,"关于LINQ,IEnumerable和iqueryable之间的区别是什么?"

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

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

可以将LINQ查询编写为LINQ方法链,反之亦然。这取决于你的喜好。

@卢卡斯:不同的是IEnumerable在内存中查询,iqueryable在内存中查询。也就是说,当您在foreach迭代器中时,您使用的是IEnumerable,当您通过扩展方法或使用linq from o in objectsynatax构建查询时,您将构建一个iqueryable。只要触摸枚举器,iqueryable就会立即执行。