关于c#:LINQ中最难或最容易被误解的方面是什么?

What's the hardest or most misunderstood aspect of LINQ?

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

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

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


延迟执行


我知道到目前为止,延迟执行的概念应该已经打动我了,但这个例子确实帮助我实际掌握了它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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("
After add:"
);
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

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

1
2
3
4
5
6
7
8
9
10
Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory


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


大O符号。Linq使编写O(n^4)算法变得非常容易,如果你不知道自己在做什么,就不会意识到它。


我认为一个Lambda表达式可以同时解析表达式树和匿名委托,因此可以将同一个声明性Lambda表达式传递给IEnumerable扩展方法和IQueryable扩展方法。


我花了很长时间才意识到许多LINQ扩展方法(如Single()SingleOrDefault()等)都有需要lambda的重载。

你可以做到:

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

不用这么说-一些糟糕的指导让我养成了这样做的习惯

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


在LinqToSQL中,我经常看到人们不理解DataContext、如何使用它以及如何使用它。太多人看不到DataContext是什么,它是工作对象的一个单元,而不是持久对象。

我见过很多时候,人们试图单独使用一个数据上下文/会话it/etc,而不是为每个操作留出新的时间。

然后在对iqueryable进行评估之前处理DataContext,但这更像是一个不了解iqueryable的人的道具,而不是DataContext。

我看到的另一个概念是查询语法与表达式语法。在这一点上,我将使用最简单的方法,通常坚持表达式语法。很多人仍然不知道他们最终会产生相同的东西,毕竟查询是编译成表达式的。


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

LINQLINQ to SQL多得多。

既然我们中的大多数人已经在托收上使用了LINQ,我们就再也不会回去了!

LINQ是.NET最重要的特性,因为2.0中的泛型和3.0中的匿名类型。

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


我个人肯定想知道我是否需要知道什么是表达树,为什么。


我最初没有意识到的是Linq语法不需要IEnumerableIQueryable来工作,Linq只是模式匹配。

alt text http://barddesmet.info/images_wlw/qisiqueryabletherlightchoiceforme_13478/image_thumb_3.png

这是答案(不,我没有写那个博客,巴特·德斯密特写的,他是我在Linq找到的最好的博客之一)。


我对林肯还比较陌生。这是我第一次尝试时遇到的问题

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


了解LINQ提供者之间的抽象何时泄漏。有些东西对对象有效,但对SQL无效(例如takewhile)。有些方法可以转换成SQL(toupper),而其他方法则不能。有些技术在对象中更有效,而其他方法在SQL中更有效(不同的连接方法)。


我仍然无法使用"let"命令(我从未找到该命令的用途)和selectmany(我使用过该命令,但我不确定是否正确)


两件事。

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

  • 好吧,由于需要,我写了一些表达的东西。我对Blogger和LiveWriter密谋将其格式化并不完全满意,但现在就这样……

    不管怎样,这是…我喜欢任何反馈,尤其是在有些地方人们需要更多的信息。

    就在这里,喜欢还是讨厌…


    有些错误消息,特别是从LINQ到SQL的错误消息可能非常令人困惑。露齿而笑

    我和其他人一样,被延期执行的死刑咬了好几次。我认为对我来说最令人困惑的事情是SQL Server查询提供程序,以及您可以和不能用它做什么。

    你不能在小数/货币列上做sum()这个事实仍然让我惊讶,因为它有时是空的。使用defaultifempty()只是不起作用。:(


    我认为在Linq中要介绍的一个很好的事情是如何让自己在性能方面陷入困境。例如,使用Linq的Count作为循环条件真的很不明智。


    iqueryable接受这两种情况,即Expression>Func,但没有给出第二种情况下性能下降的提示。

    下面是代码示例,它演示了我的意思:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [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);
    }


    我不知道这是否属于被误解——但对我来说,完全不知道。

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

    有关详细信息,请参阅此处:msdn:dataloadOptions


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


    我想说的是最被误解的(还是不被理解的?)LINQ的方面是可查询的和自定义的LINQ提供者。

    我用LINQ已经有一段时间了,在IEnumerable的世界里非常舒服,可以解决大多数LINQ的问题。

    但是当我开始查看和阅读关于iqueryable、表达式和定制Linq提供者的内容时,它让我头晕目眩。如果您希望看到一些非常复杂的逻辑,请看一下LinqToSQL是如何工作的。

    我期待着了解Linq的这一方面…


    执行查询时var代表什么?

    iQueryableiSingleResultiMultipleResult,还是根据执行情况而改变。有一些关于使用(看起来是)动态类型和C中的标准静态类型的推测。


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

    例如:

    1
    2
    3
    from outerloopitem in outerloopitems
    from innerloopitem in outerloopitem.childitems
    select outerloopitem, innerloopitem


    已编译查询

    您不能链接IQueryable,因为它们是方法调用(尽管除了SQL可翻译之外,其他什么都没有!)几乎不可能围绕它工作,这是令人难以置信的,并造成了对干燥的巨大破坏。我需要我的IQueryable用于没有编译查询的即席查询(我只编译用于重场景的查询),但是在编译的查询中,我不能使用它们,而是需要重新编写常规查询语法。现在,我在两个地方执行相同的子查询,需要记住,如果发生变化,需要同时更新这两个查询,等等。噩梦


    group by仍然使我的头旋转。

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


    我认为关于Linq to SQL的1误解是,为了有效地利用它,您仍然需要了解SQL。

    关于LinqToSQL的另一个误解是,为了使其正常工作,您仍然需要将数据库安全性降低到荒谬的程度。

    第三点是,使用LINQ to SQL和动态类(意味着类定义是在运行时创建的)会导致大量的实时编译。这绝对会扼杀性能。


    延迟加载。


    事务(不使用TransactionScope)


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

    Linq to对象和Linq to XML(IEnumerable)与Linq to SQL(IQueryable)的区别

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


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


    解释为什么Linq不像SQL语法那样简单地处理左外部联接。请参阅本文:使用LINQ实现左联接,如何:执行左外部联接(C编程指南)当我遇到这个障碍时,我非常失望,以至于我对语言的所有尊重都消失了,我觉得这只是一种很快就会消失的东西。没有一个严肃的人愿意使用缺乏这些战场证明的原始语的语法。如果您可以解释为什么不支持这些类型的设置操作。我会成为一个更好更开明的人。


    我觉得"创造表情树"很难。有很多事情困扰着我w.r.t你可以用linq,linq to sql和ado.net。


    Linq to SQL如何翻译它!

    假设我们有一个表,其中有3个字段:a、b&c(它们是整数,表名是"table1")。
    我是这样展示的:
    [a,b,c]

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

    我们有这样一个班级:

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

    然后我们这样使用它:

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

    生成的SQL查询是:

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

    它转换温度的系数。它知道我想要"row.b+row.c"(甚至更多…)放在类构造函数的"y"参数上!

    这些翻译对我很不感兴趣。我喜欢这样,我认为写这样的翻译(Linq to something)有点难!

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


    我认为您应该更详细地关注linq最常用的特性——lambda表达式和匿名类型,而不是浪费时间在"难以理解"的东西上,这些东西在现实世界的程序中很少使用。


    哪个更快,使用tsql存储过程内联linq to sql或linq to sql

    …在某些情况下,使用服务器端(存储过程)或客户端(内联LINQ)查询更好。


    理解语法"magic"。如何将理解语法转换为方法调用以及选择了什么方法调用。

    例如,如何:

    1
    2
    3
    4
    from a in b
    from c in d
    where a > c
    select new { a, c }

    转换为方法调用。


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

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


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

    一个关于LINQ的讨论可以包括一些实用的指导原则,说明何时喜欢一种语法而不是另一种,以及如何混合它们。


    当然,这不是"最困难的",而是要添加到列表中的内容:

    1
    ThenBy() extension method

    不看它的实现,我最初对它是如何工作感到困惑。每个人都很清楚逗号分隔的排序字段在SQL中是如何工作的——但就表面价值而言,我怀疑Thenby是否会做我真正希望它做的事情。它怎么能"知道"前一个排序字段是什么——看起来它应该是。

    我现在要去研究它…


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

    希望我的简要清单能有所帮助!


    您不能链接iQueryable,因为它们是方法调用(但除了SQL可翻译之外,其他什么都没有!)几乎不可能围绕它工作,这是令人难以置信的,并造成了对干燥的巨大破坏。我需要我的iqueryable用于没有编译查询的即席查询(我只有针对重场景编译的查询),但是在编译的查询中,我不能使用它们,而是需要再次编写常规查询语法。现在,我在两个地方执行相同的子查询,需要记住,如果发生变化,需要同时更新这两个查询,等等。噩梦


    我打赌几乎有人知道:您可以在LINQ查询中使用内联IFS。像这样:

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

    我想你也可以插羊羔肉,尽管我没有试过。