LINQ最难或最容易被误解的方面是什么?[关闭]


282

背景:在接下来的一个月,我会给出约或至少包括三名会谈LINQ的背景下C#。我想根据人们可能难以理解的内容,或者对他们的印象有误的情况,来了解哪些主题值得关注。我不会特别谈论LINQSQL或实体框架除了作为如何查询可以远程使用表达式树(通常被执行的例子IQueryable)。

那么,您发现了什么困难LINQ呢?您对误解有何见解?示例可能是以下任何一种,但请不要限制自己!

  • C#编译器如何处理查询表达式
  • Lambda表达式
  • 表达树
  • 扩展方式
  • 匿名类型
  • IQueryable
  • 延迟执行与立即执行
  • 流与缓冲执行(例如,OrderBy被延迟但被缓冲)
  • 隐式类型的局部变量
  • 读取复杂的通用签名(例如Enumerable.Join

3
我很想知道,当你要做的这些会谈,如果有任何的方式来查看他们的在线
马克·希思

2
第一讲:10月30日,哥本哈根。希望这将被录音。(全天!)第二讲:伦敦,11月19日晚上,伦敦.NET用户组,可能在Push LINQ上。第三讲:11月22日,开发人员开发人员日,阅读,在60分钟内实现对象的LINQ。
乔恩·斯基特

1
下载者:请添加解释性评论。
乔恩·斯基特

2
@Jon,抱歉,但是我需要关闭此窗口。
蒂姆·波斯特

3
@Tim:足够公平-仍然没有得到更多答案。我个人认为,它最终确实具有建设性,我当然认为发现人们发现棘手的内容很有用。我现在可能不会再问了……
乔恩·斯基特

Answers:


271

执行延迟


12
Righto-这显然是读者的最爱,这是此问题最重要的事情。我还会在组合中添加“缓冲与流式传输”,这是密切相关的,而且通常不会像我希望在书中看到的那样详细讨论。
乔恩·斯基特

10
真?在学习Linq的过程中,我曾多次向我指出过这种懒惰的性质,这对我来说从来都不是问题。
亚当·拉瑟克

26
同意ALassek。MSDN文档明确指出了LINQ的惰性评估性质。也许真正的问题是开发人员的懒惰编程性质... =)
Seiti

4
...尤其是当您意识到它适用于对象的LINQ而不仅仅是LINQ 2 SQL时-当您已经枚举了相同的项目列表时,您看到10个Web方法调用来检索项目列表时,您认为名单已经过评估
Simon_Weaver

5
恕我直言,知道收益声明是什么以及它如何工作对于全面了解LINQ至关重要。
peSHIr

125

我知道现在应该将延迟执行概念付诸实践,但是这个示例确实帮助我对其进行了实际掌握:

static void Linq_Deferred_Execution_Demo()
{
    List<String> items = new List<string> { "Bob", "Alice", "Trent" };

    var results = from s in items select s;

    Console.WriteLine("Before add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }

    items.Add("Mallory");

    //
    //  Enumerating the results again will return the new item, even
    //  though we did not re-assign the Linq expression to it!
    //

    Console.WriteLine("\nAfter add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

上面的代码返回以下内容:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory

2
blogs.msdn.com/b/charlie/archive/2007/12/09/…<-我认为这是解释它的最佳博客。(2007
全年

104

这里面不仅仅是更LINQSQL和功能都不仅仅是一个SQL嵌入语言解析器。


6
我讨厌每个人都这样认为:/
TraumaPony

40
并非每个人都这样!我仍然不知道什么是LINQ to SQL,并且我在该死的时间内一直使用LINQ。
罗伯特·罗斯尼

2
当我尝试使用LINQ解释某些内容时,我非常恼火,另一个人看着我说:“哦,我不使用LINQ来做类似的事情,仅使用SQL” :(
Nathan W,

13
同意,许多人似乎并不了解LINQ是通用工具。
马修·奥莱尼克

86

大O符号。如果您不知道自己在做什么,LINQ使编写O(n ^ 4)算法非常容易,而无需意识到它。


16
一个例子呢?
hughdbrown,2009年

4
就一个示例而言,也许他的意思是,让Select子句包含许多Sum()运算符非常容易,因为每个运算符都会引起整个记录集的另一次传递。
罗伯·帕克伍德

1
实际上,甚至值得仔细研究一下O表示法是什么,以及为什么它很重要,以及一些效率低下的结果查询示例。我认为这就是原始海报所暗示的内容,但我想还是要提一下。-编辑:刚刚意识到这个帖子是1.5岁:-)
zcrar70 2010年

7
那不是O(n ^ x),而是O(xn),也就是O(n)。
Malfist

3
尝试不使用join运算符进行连接将导致O(n ^ x):从range1的i1到range2的i2到range3的i3到range4的i4,其中i1 == i2 && i3 == i4选择new {i1, i2,i3,i4}。我实际上已经看过这本书了。它起作用,但是非常缓慢。
MarkPflug 2011年

55

我认为Lambda表达式可以同时解析表达式树和匿名委托,因此您可以将相同的声明式lambda表达式传递给IEnumerable<T>扩展方法和IQueryable<T>扩展方法。


2
同意 我是一位经验丰富的人,我刚刚意识到这种隐式转换正在发生,因为我开始编写自己的QueryProvider
TheSoftwareJedi

53

把我的方式很长时间才意识到,很多LINQ扩展方法,如Single()SingleOrDefault()等有需要lambda表达式重载。

你可以做 :

Single(x => x.id == id)

不必这么说-某些不好的教程使我养成了这样做的习惯

Where(x => x.id == id).Single()

+1,非常好。我会记住的。
椒盐脆饼2010年

4
我也一直忘记这一点。的,也是如此Count()。您是否知道除了明显的代码可读性之外,是否还有任何性能差异?
贾斯汀·摩根

1
在大学里,我的讲师想通过使用这些超载获得积分!!我证明他错了!
TDaver

12
听起来可能很奇怪,但我更喜欢第二种语法。我觉得它更具可读性。
Konamiman

40

在LINQ to SQL中,我经常看到人们不了解DataContext,如何使用它以及应该如何使用它。太多的人看不到DataContext是什么,它是工作单元对象,而不是持久性对象。

我见过很多次人们试图单选一个DataContext /会话,而不是为每个操作腾出新的时间。

然后,在对IQueryable进行评估之前要先处理DataContext,但这更多的是人们比DataContext还不了解IQueryable。

我发现与另一个概念混淆的是查询语法与表达式语法。在这一点上,我将使用最简单的方法,通常会坚持使用表达式语法。很多人仍然没有意识到他们最终会产生相同的结果,毕竟将Query编译为Expression。


2
警告:工作单元可以是一个小型程序,其数据上下文为单例。
08年

15
您不应该单独使用DataContext,因为它不是线程安全的。
亚伦·鲍威尔,

3
@Slace,并非所有程序都是多头的,因此可以将DataContext作为很多“桌面”软件
Ian Ringrose中

2
当我做我的第一个LINQ to SQL项目时,就被这个问题咬住了(使用DataContext作为单例)。我认为文档和书籍不足以使这一点变得显而易见。实际上,我认为这个名称可以改进,但是我不确定如何。
罗杰·利普斯科姆2010年

1
花了好几次在Linq上阅读ScottGu的文章,才把它弄得一团糟。
Evan Plaice 2010年

34

我认为LINQ 误解部分是它是语言扩展,而不是数据库扩展或构造。

LINQ远远不止是LINQ to SQL

现在,我们大多数人都LINQ在收藏中使用过,我们再也回不去了!

LINQ 是自2.0版泛型和3.0版匿名类型以来,.NET的最重要功能。

现在我们有了Lambda,我已经等不及了并行编程!


我什至认为它比匿名类型更重要,甚至可能比泛型更重要。
贾斯汀·摩根

26

我肯定想知道我是否需要知道什么是表达式树,以及为什么。


6
我认为有必要知道什么是表达式树以及为什么存在它们,但是不知道如何自己构建它们的细节。(它们很容易手工构建,但是编译器在转换lambda表达式时会做得很好。)
Jon Skeet

3
实际上,我正在考虑在表达式树上创建一些博客条目(因为我确实“获取”了它们)。我发现操纵表情树非常有用...
Marc Gravell

但是,我认为这对乔恩的演讲没有帮助;-p
马克·

3
我只是担心表达式树会变得像yield语句:尽管我一开始并不了解它的用途,但事实却证明它非常有价值。
罗伯特·罗斯尼

1
Marc Gravell我很想阅读您关于该主题的博客文章。期待它
Alexandre Brisebois

20

我是LINQ的新手。这是我第一次尝试时偶然发现的东西

  • 将几个查询合并为一个
  • 在Visual Studio中有效调试LINQ查询。

21
调试LINQ本身就是一个主题,也是一个重要的主题。我认为LINQ的最大缺点在于,它使您可以编写无法逐步执行的任意复杂逻辑块。
罗伯特·罗斯尼

3
这些可能是使用LINQ垫的好地方
Maslow

2
衷心同意;这就是为什么我写了LINQ Secrets Revealed:Chaining and Debugging(刚刚发布在Simple-Talk.com上)的原因,您可能会从中找到帮助。
Michael Sorens 2010年

是的,LinqPad是用于开发LINQ查询的出色辅助工具。尤其是在起步时,您不熟悉约定/模式。
布法罗2010年

20

东西我最初不意识到的是,LINQ的语法并不需要IEnumerable<T>IQueryable<T>工作,LINQ是只是模式匹配。

替代文字http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

这是答案(不,我没有写那个博客,Bart De Smet也是,他是我发现的LINQ上最好的博客之一)。


1
:您可能也发现这个博客帖子有趣msmvps.com/blogs/jon_skeet/archive/2008/02/29/...
乔恩斯基特

乔恩(Non)的好帖子(虽然最近才订阅您的博客)。
亚伦·鲍威尔,

19

我仍然对“ let”命令(我从未发现过使用)和SelectMany(我已经使用过,但不确定执行是否正确)感到麻烦。


2
每当您要引入变量时,都可以使用let语句。想想一个传统的循环,您在其中引入变量并为每个变量命名,以提高代码的可读性。有时候,在让let语句评估函数结果的地方也很不错,然后您可以选择并按顺序排序,而不必两次评估结果。
罗伯·帕克伍德

“ let”允许您执行复合类型。方便的东西。
菲尔

19

了解Linq提供程序之间的抽象何时泄漏。有些事情对对象有效,但对SQL不起作用(例如.TakeWhile)。有些方法可以转换为SQL(ToUpper),而另一些则不能。有些技术在对象中效率更高,而其他技术在SQL中效率更高(不同的联接方法)。


1
这是非常好的一点。Intellisense不能向您显示所有这些内容,通常甚至可以进行编译也无济于事。然后,您会在运行时崩溃。我希望VS 2010在显示相关扩展方法方面做得更好。
詹森·肖特


11

好的,由于需求,我写了一些Expression东西。我对Blogger和LiveWriter密谋格式化的方式并不满意,但现在就可以了...

无论如何,这里...我希望收到任何反馈,尤其是在某些地方人们需要更多信息的情况下。

在这里,喜欢还是讨厌...


10

一些错误消息,尤其是从LINQ到SQL的错误消息可能会造成混乱。咧嘴

像其他所有人一样,我被延期执行所困扰。我认为对我来说最令人困惑的是SQL Server查询提供程序以及您可以使用或不能使用的功能。

您仍然无法对有时为空的十进制/货币列执行Sum(),这仍然让我感到惊讶。使用DefaultIfEmpty()只是行不通。:(


1
谢尔·普雷特(Shold beprette)容易在查询中拍些地方以求和
埃斯本·斯科夫·

9

我认为LINQ的一个重要方面是如何使自己陷入麻烦的性能方面。例如,使用LINQ的计数作为循环条件确实非常不明智。


7

该IQueryable既接受Expression<Func<T1, T2, T3, ...>>Func<T1, T2, T3, ...>,也没有暗示第二种情况下的性能下降。

这是代码示例,演示了我的意思:

[TestMethod]
public void QueryComplexityTest()
{
    var users = _dataContext.Users;

    Func<User, bool>                funcSelector =       q => q.UserName.StartsWith("Test");
    Expression<Func<User, bool>>    expressionSelector = q => q.UserName.StartsWith("Test");

    // Returns IEnumerable, and do filtering of data on client-side
    IQueryable<User> func = users.Where(funcSelector).AsQueryable();
    // Returns IQuerible and do filtering of data on server side
    // SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
    IQueryable<User> exp = users.Where(expressionSelector);
}

你可以解释吗?我没有关注...
Pretzel

@Pretzel我添加了代码示例,用以演示我的问题。
Valera Kolupaev

感谢您的代码示例!非常有帮助。
布法罗2010年

6

我不知道它是否被误解了-但是对我来说,只是未知数。

我很高兴了解DataLoadOptions,以及在进行特定查询时如何控制要联接的表。

有关更多信息,请参见此处:MSDN:DataLoadOptions


6

我想说的是,LINQ最容易被误解的(或者应该不被理解?)方面是IQueryable自定义LINQ提供程序

我已经使用LINQ已有一段时间了,并且在IEnumerable世界中非常满意,并且可以使用LINQ解决大多数问题。

但是,当我开始研究并阅读有关IQueryable,表达式和自定义linq提供程序的信息时,我大为吃惊。如果您想了解一些非常复杂的逻辑,请看一下LINQ to SQL的工作方式。

我期待了解LINQ的这一方面。


6

正如大多数人所说,我认为最容易理解的部分是假设LINQ只是T-SQL的替代品。我的经理认为自己是TSQL专家,不会让我们在项目中使用LINQ,甚至不喜欢MS发布这种东西!!!


太多的人用它代替TSQL。他们大多数人从未听说过执行计划。
erikkallen

+1是因为我同意您的经理的说法,至少在允许任何项目中使用LINQ to SQL的范围内。LINQ to Objects完全是另一回事。
NotMe 2010年

5

var在执行查询时代表什么?

是吗 iQueryableiSingleResultiMultipleResult,或者它是否在改变基础上实施。关于在C#中使用(看起来是)动态类型与标准静态类型的一些猜测。


AFAIK var始终是有问题的具体类(即使它是匿名类型),因此它永远都不是 IQueryable,ISingleResult或以“ I”开头的任何内容(以“ I”开头的具体类不必应用)。
Motti

5

我不认为每个人都能理解嵌套循环的难易程度。

例如:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem

+1,哇。那非常强大。
椒盐脆饼2010年

4

group by 仍然使我的头旋转。

关于延迟执行的任何混淆都应该能够通过逐步执行一些基于LINQ的简单代码并在监视窗口中进行操作来解决。


1
我发现有趣地实现很多LINQ to Objects确实有帮助:)但是,是的,这有点令人困惑-当然,如果我有一段时间没有做任何LINQ了,我必须回到签名。同样,“加入”与“加入进入”常常让我...
乔恩·斯基特

4

编译查询

你不能链的事实IQueryable,因为他们是方法调用(虽然没有别的但SQL意译的!),而这几乎是不可能解决它是mindboggling并造成了巨大的违反干的。我需要IQueryable临时的查询,其中没有编译查询(我只对繁重的场景有编译查询),但是在编译查询中,我无法使用它们,而需要再次编写常规查询语法。现在,我在2个地方执行相同的子查询,需要记住,如果发生更改,请同时进行更新,依此类推。一个噩梦。


4

我认为关于LINQ to SQL的#1误解是您仍然必须了解SQL才能有效地使用它。

关于Linq to Sql的另一个误解是,您仍然必须将数据库安全性降低到荒谬的程度,才能使其正常工作。

第三点是,将Linq to Sql与动态类一起使用(意味着类定义是在运行时创建的)会导致大量的即时编译。绝对可以杀死性能。


4
但是,已经知道SQL是非常有益的。Linq向SQL(以及其他ORM)发出的某些SQL可能完全令人怀疑,并且了解SQL有助于诊断此类问题。另外,Linq to SQL可以利用存储过程。
罗伯特·哈维


2

如前所述,延迟加载和延迟执行

LINQ to Object和LINQ to XML(IEnumerable)与LINQ to SQL(IQueryable)有何不同

如何在所有层中使用LINQ构建数据访问层,业务层和表示层...以及一个很好的示例。


前两个我能做。我不想尝试以“这是正确的方式”做第三件事……
Jon Skeet

+1,直到您指出,我才意识到LINQ-to-Objects和LINQ-to-XML是IEnumerable的,而不是LINQ-to-SQL是IQueryable的,但是这是有道理的。谢谢!
椒盐脆饼2010年

2

正如大多数人所说,我认为最容易理解的部分是假设LINQ只是T-SQL的替代品。我的经理将自己视为TSQL专家,不会让我们在项目中使用LINQ,甚至不愿让MS发布这样的事情!!!


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.