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

Posted

技术标签:

【中文标题】LINQ 最难或最容易被误解的方面是啥? [关闭]【英文标题】:What's the hardest or most misunderstood aspect of LINQ? [closed]LINQ 最难或最容易被误解的方面是什么? [关闭] 【发布时间】:2008-10-18 20:47:40 【问题描述】:

背景:在接下来的一个月里,我将在C# 的背景下进行三场关于或至少包括LINQ 的讨论。我想知道哪些主题值得给予相当多的关注,基于人们可能难以理解的内容,或者他们可能有错误的印象。我不会专门讨论 LINQSQL 或实体框架,除非作为如何使用表达式树(通常是 IQueryable)远程执行查询的示例。

那么,您对LINQ 有什么困难?你在误解方面看到了什么?示例可能有以下任何一种,但请不要限制自己!

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

【问题讨论】:

我很想知道你什么时候做这些演讲,以及是否有任何方法可以在线查看它们 第一次演讲:哥本哈根,10 月 30 日。希望这会被录音。 (一整天!)第二次谈话:伦敦,11 月 19 日晚上,伦敦 .NET 用户组,可能在 Push LINQ 上。第三次演讲:阅读,11 月 22 日,开发者开发者日,在 60 分钟内实现 LINQ to Objects。 反对者:请添加解释性评论。 @Jon,对不起,我需要关闭它。 @Tim:很公平——反正它没有得到更多答案。就我个人而言,我认为它确实最终具有建设性,请注意——我当然发现了解人们觉得棘手的地方很有用。不过我现在可能不会问了…… 【参考方案1】:

延迟执行

【讨论】:

Righto - 这显然是读者最喜欢的,这是这个问题最重要的事情。我还将在组合中添加“缓冲与流”,因为这是密切相关的 - 并且通常没有像我希望在书中看到的那样详细讨论。 真的吗?在学习 Linq 时,我曾多次向我指出它的懒加载性质,这对我来说从来都不是问题。 同意 ALassek。 MSDN 文档清楚地说明了 LINQ 的惰性求值性质。也许真正的问题是开发人员的懒惰编程性质... =) ... 特别是当您意识到它适用于 LINQ to objects 而不仅仅是 LINQ 2 SQL - 当您看到 10 个 Web 方法调用来检索项目列表时,您已经在枚举它相同的项目列表,您认为该列表已被评估 了解什么是 yield 语句以及它是如何工作的,恕我直言,这对于彻底了解 LINQ 至关重要。【参考方案2】:

我知道延迟执行的概念现在应该被我打败了,但是这个例子确实帮助我实际掌握了它:

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

【讨论】:

blogs.msdn.com/b/charlie/archive/2007/12/09/… 【参考方案3】:

不仅仅是LINQSQL,而且功能不仅仅是嵌入在语言中的SQL 解析器。

【讨论】:

我讨厌每个人都这么想:/ 不是每个人都这样做!我仍然不知道 LINQ to SQL 是什么,而且我一直在使用 LINQ。 当我尝试使用 LINQ 解释某些事情时,我感到非常恼火,而其他人只是看着我说“哦,我不使用 LINQ 来做类似的事情,只有 SQL”:(跨度> 同意,很多人似乎不明白 LINQ 是一种通用工具。【参考方案4】:

Big O notation。如果您不知道自己在做什么,LINQ 让您在不知不觉中编写 O(n^4) 算法变得异常容易。

【讨论】:

举个例子怎么样? 就一个例子而言,也许他的意思是这样一个事实很容易让 Select 子句包含许多 Sum() 运算符,每个运算符都会导致整个记录集的另一次传递。 事实上,甚至可能值得了解一下大 O 表示法是什么以及它为何如此重要,以及一些低效查询示例。我认为这就是原始海报所暗示的,但我想我还是会提到它。 -- 编辑:刚刚意识到这篇文章已经有 1.5 年的历史了 :-) 不会是 O(n^x),而是 O(xn),也就是 O(n)。 尝试在没有连接运算符的情况下进行连接将导致 O(n^x): from i1 in range1 from i2 in range2 from i3 in range3 from i4 in range4 where i1 == i2 && i3 == i4 选择新的 i1, i2, i3, i4。我以前真的看过这个。它可以工作,但速度很慢。【参考方案5】:

我认为Lambda 表达式可以解析为表达式树和匿名委托这一事实,因此您可以将相同的声明性lambda 表达式传递给IEnumerable&lt;T&gt; 扩展方法和IQueryable&lt;T&gt; 扩展方法。

【讨论】:

同意。我是一名老手,当我开始编写自己的 QueryProvider 时,我才意识到这种隐式转换正在发生【参考方案6】:

方式让我意识到许多 LINQ 扩展方法(例如 Single()SingleOrDefault() 等)都有需要 lambda 的重载。

你可以这样做:

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

而且不需要这么说 - 一些糟糕的教程让我养成了这样做的习惯

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

【讨论】:

+1,非常好。我会记住的。 我也一直忘记这一点。 Count() 等也是如此。除了代码可读性的明显好处之外,您知道是否有任何性能差异? 在大学里,我的讲师想因使用这些重载而扣分!!我已经证明他错了! 这听起来可能很奇怪,但我更喜欢第二种语法。我觉得它更具可读性。【参考方案7】:

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

我已经看到很多次人们试图单例化 DataContext/会话它/等等,而不是为每个操作创建一个新的时间。

然后在 IQueryable 被评估之前处理 DataContext ,但这更多的是人们不了解 IQueryable 而不是 DataContext。

我看到很多混淆的另一个概念是查询语法与表达式语法。我将使用当时最简单的方法,通常坚持使用表达式语法。很多人还没有意识到最终会产生同样的东西,Query毕竟是编译成Expression的。

【讨论】:

警告:工作单元可以是一个数据上下文为单例的小程序。 你不应该在单例中使用 DataContext,它不是线程安全的。 @Slace,并不是所有的程序都是多头的,所以在很多“桌面”软件中将 DataContext 作为单例是可以的 当我做我的第一个 LINQ to SQL 项目时,我被这个(使用 DataContext 作为单例)所困扰。我认为文档和书籍还不够明显。实际上,我认为名称可以改进,但我不确定如何。 我在 Linq 上多次阅读 ScottGu 的文章后才把这件事深深地印在了我的脑海里。【参考方案8】:

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

LINQ 远比LINQ to SQL 多。

现在我们大多数人都在收藏中使用了LINQ,我们永远不会回去!

LINQ 是 .NET 自 2.0 中的泛型和 3.0 中的匿名类型以来最重要的一个特性。

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

【讨论】:

我什至认为它比匿名类型更重要,甚至可能比泛型更重要。【参考方案9】:

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

【讨论】:

我认为值得了解什么是表达式树以及它们存在的原因,而不是如何自己构建它们的细节。 (手动构建它们很痛苦,但编译器在转换 lambda 表达式时会做得很好。) 实际上,我正在考虑在表达式树上写一些博客文章(因为我确实“得到”了它们)。我发现操纵表达式树非常有用... 但是,我认为它们对 Jon 的演讲没有帮助;-p 我只是担心表达式树会像 yield 语句一样:尽管我一开始并不明白它的用途,但事实证明它非常有价值。 Marc Gravell 我很想阅读您关于该主题的博客文章。敬请期待【参考方案10】:

我对 LINQ 还很陌生。这是我第一次尝试时偶然发现的事情

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

【讨论】:

调试 LINQ 本身就是一个话题,也是一个重要的话题。我认为 LINQ 的最大弱点是它允许您编写无法单步执行的任意复杂逻辑块。 这些可能是使用 LINQ pad 的好地方 衷心同意;这就是为什么我写了LINQ Secrets Revealed: Chaining and Debugging,刚刚在 Simple-Talk.com 上发布,您可能会找到帮助。 是的,LinqPad 是用于开发 LINQ 查询的绝佳辅助工具。尤其是当您刚开始使用约定/模式时。【参考方案11】:

我最初没有意识到 LINQ 语法不需要需要IEnumerable&lt;T&gt;IQueryable&lt;T&gt; 才能工作,LINQ 只是关于模式匹配。

alt text http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

Here is the answer(不,我没有写过那个博客,Bart De Smet 做了,他是我发现的 LINQ 上最好的博主之一)。

【讨论】:

您可能会觉得这篇博文也很有趣:msmvps.com/blogs/jon_skeet/archive/2008/02/29/… Jon 的帖子不错(我确实订阅了你的博客,不过最近才订阅)。【参考方案12】:

我仍然无法使用“let”命令(我从来没有发现它的用途)和 SelectMany(我用过,但我不确定我做对了)

【讨论】:

任何时候你想引入一个变量,你都可以使用 let 语句。考虑一个传统的循环,您在其中引入变量并为每个变量命名以提高代码的可读性。有时,如果您有一个评估函数结果的 let 语句也很不错,然后您可以选择并按 on 排序,而不必对结果进行两次评估。 'let' 允许你做复合类型。方便的东西。【参考方案13】:

了解 Linq 提供程序之间的抽象何时泄漏。有些事情适用于对象,但不适用于 SQL(例如,.TakeWhile)。有些方法可以翻译成 SQL (ToUpper),而有些则不能。有些技术在对象中更有效,而另一些在 SQL 中更有效(不同的连接方法)。

【讨论】:

这是一个非常好的观点。 Intellisense 将向您展示所有这些并没有帮助,它通常甚至可以编译。然后你在运行时爆炸。我希望 VS 2010 在展示相关扩展方法方面做得更好。【参考方案14】:

几件事。

    人们将 Linq 视为 Linq to SQL。 有些人认为他们可以开始用 Linq 查询替换所有 foreach/logic 而不考虑这种性能影响。

【讨论】:

【参考方案15】:

好的,由于需求,我已经写了一些表达式的东西。我不是 100% 满意博主和 LiveWriter 如何合谋格式化它,但它现在可以......

不管怎样,就这样吧...我希望得到任何反馈,尤其是在人们需要更多信息的领域。

Here it is,喜欢还是讨厌...

【讨论】:

【参考方案16】:

一些错误消息,尤其是从 LINQ 到 SQL 的错误消息,可能会非常令人困惑。 咧嘴一笑

我和其他人一样被推迟执行几次。我认为对我来说最令人困惑的是 SQL Server 查询提供程序以及您可以使用它做什么和不能做什么。

我仍然对您不能对有时为空的小数/货币列执行 Sum() 感到惊讶。使用 DefaultIfEmpty() 是行不通的。 :(

【讨论】:

应该很容易在该查询上打一个 Where 以使 sum 起作用【参考方案17】:

我认为在 LINQ 中要介绍的一件好事是如何让自己在性能方面陷​​入困境。例如,使用 LINQ 的计数作为循环条件真的非常不聪明。

【讨论】:

【参考方案18】:

IQueryable 同时接受Expression&lt;Func&lt;T1, T2, T3, ...&gt;&gt;Func&lt;T1, T2, T3, ...&gt;,而不提示在第二种情况下性能下降。

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

[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 我添加了代码示例,演示了我的问题。 感谢代码示例!很有帮助。【参考方案19】:

我不知道它是否被误解——但对我来说,简直是未知数。

我很高兴了解 DataLoadOptions 以及在进行特定查询时如何控制连接哪些表。

查看这里了解更多信息:MSDN: DataLoadOptions

【讨论】:

【参考方案20】:

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

我使用 LINQ 已经有一段时间了,完全适应 IEnumerable 世界,并且可以使用 LINQ 解决大多数问题。

但是,当我开始研究和阅读 IQueryable、表达式和自定义 linq 提供程序时,它让我头晕目眩。如果您想了解一些非常复杂的逻辑,请查看 LINQ to SQL 的工作原理。

我期待了解 LINQ 的这方面...

【讨论】:

【参考方案21】:

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

【讨论】:

太多人用它来代替 TS​​QL。他们中的大多数人从未听说过执行计划。 +1 因为我同意你的经理,至少在任何项目中允许 LINQ to SQL 的范围内。 LINQ to Objects 完全是另一回事。【参考方案22】:

执行查询时 var 代表什么?

iQueryableiSingleResultiMultipleResult,还是根据实现而改变。有一些关于在 C# 中使用(似乎是)动态类型与标准静态类型的猜测。

【讨论】:

AFAIK var 始终是有问题的具体类(即使它是匿名类型),因此它是 never IQueryable、ISingleResult 或以“I”开头的任何内容(具体类开头'我'不需要申请)。【参考方案23】:

嵌套循环是多么容易,我认为不是每个人都理解的。

例如:

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

【讨论】:

+1,哇。这很强大。【参考方案24】:

group by 仍然让我头晕目眩。

对deferred execution 的任何困惑都应该能够通过逐步执行一些基于 LINQ 的简单代码并在监视窗口中进行操作来解决。

【讨论】:

我发现为了好玩而实现相当多的 LINQ to Objects 确实有帮助 :) 但是,是的,这有点令人困惑——当然,如果我有一段时间没有做过任何 LINQ,我有回到签名。同样,“加入”与“加入”经常让我...【参考方案25】:

编译查询

您不能链接 IQueryable,因为它们是方法调用(而 仍然除了 SQL 可翻译之外别无他物!)而且几乎不可能解决它的事实令人难以置信并创建严重违反 DRY。我需要我的 IQueryable's 用于临时查询,其中我没有编译查询(我只为繁重的场景编译查询),但在编译查询中我不能使用它们,而是需要编写常规查询再次语法。现在我在 2 个地方做相同的子查询,如果有变化,需要记住更新这两个地方,等等。一场噩梦。

【讨论】:

【参考方案26】:

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

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

第三点是使用 Linq to Sql 和动态类(意味着类定义是在运行时创建的)会导致大量的即时编译。这绝对会影响性能。

【讨论】:

不过,了解 SQL 是非常有益的。由 Linq to SQL(和其他 ORM)发出的一些 SQL 可能是完全可疑的,了解 SQL 有助于诊断此类问题。此外,Linq to SQL 可以使用存储过程。【参考方案27】:

延迟加载。

【讨论】:

类似于***.com/questions/215548/…【参考方案28】:

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

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

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

【讨论】:

前两个我能做到。我还不想尝试以“这是正确的方式”的方式做第三个...... +1,在您指出之前,我没有意识到 LINQ-to-Objects 和 LINQ-to-XML 是 IEnumerable 而不是 LINQ-to-SQL 作为 IQueryable,但它使感觉。谢谢!【参考方案29】:

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

【讨论】:

【参考方案30】:

事务(不使用 TransactionScope)

【讨论】:

以上是关于LINQ 最难或最容易被误解的方面是啥? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

您最喜欢的非内置 LINQ to Objects 运算符是啥? [关闭]

为啥使用 EF / Linq to sql 创建性能不佳的查询如此容易[关闭]

“关联表”(多对多关系)的正确名称是啥[关闭]

LINQ to entity中的一些误解

为什么我说做好项目管理不容易?

我是不是误解了 LINQ to SQL .AsEnumerable()?