LINQ中最难或最容易被误解的方面是什么?

时间:2008-10-18 20:47:40

标签: c# linq c#-3.0

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

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

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

42 个答案:

答案 0 :(得分:271)

延迟执行

答案 1 :(得分: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 :(得分:104)

只有LINQSQL并且这些功能不仅仅是嵌入在该语言中的SQL解析器。

答案 3 :(得分:86)

Big O notation。如果你不知道你在做什么,那么LINQ可以非常容易地编写O(n ^ 4)算法而不会意识到它。

答案 4 :(得分:55)

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

答案 5 :(得分:53)

让我方式太长时间才意识到许多LINQ扩展方法(例如Single()SingleOrDefault()等)都有带lambda的重载。

你可以这样做:

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

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

的习惯
Where(x => x.id == id).Single()

答案 6 :(得分:40)

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

我已经看过很多次人们试图将DataContext / session一起单独化,而不是为每个操作创造新的时间。

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

我看到很多混淆的另一个概念是查询语法与表达式语法。我将使用哪个是最容易的,通常坚持使用表达式语法。很多人还没有意识到他们最终会生成相同的东西,查询毕竟被编译成Expression。

答案 7 :(得分:34)

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

LINQ远远超过LINQ to SQL

现在我们大多数人都在集合上使用过LINQ,我们永远不会回去!

自从2.0中的Generics和3.0中的匿名类型以来,

LINQ是.NET最重要的特性。

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

答案 8 :(得分:26)

我肯定想知道我是否需要知道树的表达方式,以及原因。

答案 9 :(得分:20)

我对LINQ很新。这是我第一次尝试偶然发现的事情

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

答案 10 :(得分:20)

我最初没有意识到的是LINQ语法需要IEnumerable<T>IQueryable<T>才能工作,LINQ只是模式匹配。

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

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

答案 11 :(得分:19)

了解Linq提供程序中的抽象何时泄漏。有些东西可以处理对象而不是SQL(例如.TakeWhile)。有些方法可以转换为SQL(ToUpper)而其他方法则不能。某些技术在其他人在SQL中更有效的对象(不同的连接方法)中更有效。

答案 12 :(得分:19)

我仍然遇到“let”命令(我从来没有找到用途)和SelectMany(我已经使用过,但我不确定我做得对)的问题。

答案 13 :(得分:12)

一些事情。

  1. 人们认为Linq是Linq to SQL。
  2. 有些人认为他们可以开始用Linq查询替换所有foreach /逻辑,而不考虑这种性能影响。

答案 14 :(得分:11)

好的,由于需求,我已经写了一些Expression的东西。我对博主和LiveWriter如何密谋对其进行格式化并不是百分之百的满意,但它现在也会这样做......

无论如何,这里有...我喜欢任何反馈,特别是如果有人想要更多信息的地方。

Here it is,喜欢或讨厌它......

答案 15 :(得分:10)

一些错误消息,尤其是从LINQ到SQL的错误消息可能会让人感到困惑。 笑容

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

我仍然对你不能在有时为空的小数/金钱列上做Sum()这一事实感到惊讶。使用DefaultIfEmpty()只是行不通。 :(

答案 16 :(得分:9)

我认为在LINQ中要做的一件好事就是如何让你自己在性能方面遇到麻烦。例如,使用LINQ的计数作为循环条件实际上非常不聪明。

答案 17 :(得分: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);
}

答案 18 :(得分:6)

我不知道它是否有资格被误解 - 但对我来说,只是未知。

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

有关详细信息,请参阅此处:MSDN: DataLoadOptions

答案 19 :(得分:6)

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

我已经使用LINQ了一段时间,并且在IEnumerable世界中完全感到舒服,并且可以解决LINQ的大多数问题。

但是当我开始查看和阅读有关IQueryable,Expressions和自定义linq提供程序时,它让我头晕目眩。如果你想看到一些非常复杂的逻辑,请看看LINQ to SQL是如何工作的。

我期待理解LINQ的这一方面...

答案 20 :(得分:6)

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

答案 21 :(得分:5)

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

例如:

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

答案 22 :(得分:5)

执行查询时var代表什么?

iQueryableiSingleResultiMultipleResult还是根据实施情况进行更改。关于使用(似乎是什么)动态类型与C#中的标准静态类型有一些猜测。

答案 23 :(得分:4)

group by仍然让我头晕目眩。

关于deferred execution的任何疑惑应该能够通过逐步完成一些简单的基于LINQ的代码并在观察窗口中进行游戏来解决。

答案 24 :(得分:4)

我认为关于LINQ to SQL的#1误解是你仍然需要知道SQL才能有效地使用它。

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

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

答案 25 :(得分:4)

编译查询

你不能链接IQueryable,因为它们是方法调用(而仍然除了SQL可翻译之外别无其他!)并且几乎不可能解决这个事实是令人难以置信的事实并造成严重违反DRY的行为。我需要我的IQueryable用于ad-hoc,其中我没有编译查询(我只为重度场景编译查询),但在编译查询中我不能使用它们而是需要编写再次定期查询语法。现在我在2个地方做同样的子查询,如果有什么变化需要记住更新两者,等等。一场噩梦。

答案 26 :(得分:2)

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

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

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

答案 27 :(得分:2)

延迟加载。

答案 28 :(得分:2)

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

答案 29 :(得分:2)

交易(不使用TransactionScope)

答案 30 :(得分:1)

我发现“创建表达式树”很难。有很多事情让我感到害怕,你可以使用LINQ,LINQ to SQL和ADO.Net来完成任务。

答案 31 :(得分:1)

LINQ to SQL如何翻译它!

假设我们有一个包含3个字段的表; A,B&amp; C(它们是整数,表名是“Table1”) 我这样表现出来:
[A,B,C]

现在我们想得到一些结果如下:
[X = A,Y = B + C]

我们有这样一个班级:

public class Temp
{
   public Temp(int x, int y)
   {
      this.X = x;
      this.Y = y;
   }

   public int X { get; private set; }
   public int Y { get; private set; }
}

然后我们像这样使用它:

using (MyDataContext db = new MyDataContext())
{
   var result = db.Table1.Select(row => 
                   new Temp(row.A, row.B + row.C)).ToList();
}

生成的SQL查询是:

SELECT [t0].[A] AS [x], [t0].[B] + [t0].[C] AS [y]
FROM [Table1] AS [t0]

它翻译了Temp的.ctor。它知道我想要“row.B + row.C”(甚至更多......)来加入我的类构造函数的“y”参数!

这些翻译对我很感兴趣。我喜欢这样,我认为编写这样的翻译器(LINQ to Something)有点难!

当然!这是一个坏消息:LINQ to Entities(4.0)不支持带参数的构造函数。 (为什么不呢?)

答案 32 :(得分:1)

我觉得有点令人失望的是查询表达式语法只支持LINQ功能的一个子集,所以你不能不时地避免链接扩展方法。例如。无法使用查询表达式语法调用Distinct方法。要使用Distinct方法,您需要调用扩展方法。另一方面,查询表达式语法在很多情况下非常方便,因此您也不想跳过它。

有关LINQ的讨论可能包含一些实用指南,指出何时优先使用一种语法而不是另一种语法以及如何混合它们。

答案 33 :(得分:1)

解释为什么Linq不像sql语法那样处理左外连接。 查看此文章:Implementing a Left Join with LINQHow to: Perform Left Outer Joins (C# Programming Guide) 当我遇到这个障碍时,我非常失望,我对语言的所有尊重都消失了,而且我认为它只是很快会逐渐消失的东西。没有严肃的人会想要使用缺乏这些经过战场验证的原语的语法。如果你能解释为什么不支持这种设置操作。我会成为一个更好,更开放的人。

答案 34 :(得分:1)

我发现很难找到关于匿名类型的明确信息,特别是关于Web应用程序的性能。 此外,我建议更好和实用的Lamda表达式示例和查询和性能相关主题中的“如何”部分。

希望我的简短列表能够提供帮助!

答案 35 :(得分:1)

我认为你应该更多地关注LINQ最常用的功能 - Lambda表达式和匿名类型,而不是浪费时间在“难以理解”的东西上,这些东西在现实世界的程序中很少使用。

答案 36 :(得分:1)

哪个更快,使用Tsql Sprocs的内联Linq-to-Sql或Linq-to-Sql

...并且有些情况下最好使用服务器端(Sproc)或客户端(内联Linq)查询。

答案 37 :(得分:1)

理解语法'魔术'。如何将理解语法转换为方法调用以及选择哪种方法调用。

如何:例如:

from a in b
from c in d
where a > c
select new { a, c }

被翻译成方法调用。

答案 38 :(得分:1)

这当然不是“最难的”,只是要添加到列表中的内容:

ThenBy() extension method

不看它的实现,我最初对它是如何工作感到困惑。每个人都很清楚逗号分隔的排序字段在SQL中是如何工作的 - 但从表面上来看,我怀疑ThenBy会做我真正希望它做的事情。它怎么能“知道”以前的排序字段是什么 - 它似乎应该如此。

我现在要研究它......

答案 39 :(得分:1)

对于LINQ2SQL:了解一些生成的SQL并编写转换为良好(快速)SQL的LINQ查询。这是知道如何平衡LINQ查询的声明性质和它们在已知环境(SQL Server)中快速执行所需的真实性这一大问题的一部分。

通过更改LINQ代码中的微小内容,您可以获得完全不同的SQL生成查询。如果要基于条件语句创建表达式树(即添加可选的过滤条件),则会特别危险。

答案 40 :(得分:0)

你不能将IQueryable链接起来,因为它们是方法调用(虽然它只是SQL可翻译!)并且几乎不可能解决它是令人难以置信的并且造成严重违反DRY。我需要我的IQueryable用于ad-hoc,其中我没有编译查询(我只对重度场景编译查询),但在编译查询中我不能使用它们而是需要再次编写常规查询语法。现在我在2个地方做同样的子查询,如果有什么变化需要记住更新两者,等等。一场噩梦。

答案 41 :(得分:-1)

我几乎打赌的东西知道:你可以在linq查询中使用内联ifs。像这样:

var result = from foo in bars where (
    ((foo.baz != null) ? foo.baz : false) &&
    foo.blah == "this")
    select foo;

我想你也可以插入lambdas,虽然我还没试过。