我错过了一些关于 LINQ 的东西吗?

Posted

技术标签:

【中文标题】我错过了一些关于 LINQ 的东西吗?【英文标题】:Am I missing something about LINQ? 【发布时间】:2010-09-06 11:35:36 【问题描述】:

我似乎遗漏了一些关于 LINQ 的内容。对我来说,它似乎将 SQL 的一些我最不喜欢的元素转移到 C# 语言中并将它们用于其他事情。

我的意思是,我可以看到在数据库以外的事物上使用类似 SQL 的语句的好处。但是,如果我想编写 SQL,那么为什么不直接编写 SQL 并将其排除在 C# 之外呢?我在这里错过了什么?

【问题讨论】:

【参考方案1】:

LINQ 与 SQL 无关。 LINQ 是关于在对象上应用函数式编程范例。

LINQ to SQL 是建立在 LINQ 基础之上的 ORM,但 LINQ 远不止于此。我不使用 LINQ to SQL,但我一直使用 LINQ。

承担寻找两个列表交集的任务:

在 LINQ 之前,此任务需要编写一个嵌套的 foreach,它为大列表中的每个项目迭代一次小列表 O(N*M),并且需要大约 10 行代码。

foreach (int number in list1)

    foreach (int number2 in list2)
    
        if (number2 == number)
        
            returnList.add(number2);
        
    

使用 LINQ,它在一行代码中做同样的事情:

var results = list1.Intersect(list2);

您会注意到它看起来不像 LINQ,但确实如此。如果您不想使用表达式语法,则无需使用。

【讨论】:

这很好,谢谢。我很感兴趣,在您的两个代码示例中,LINQ 版本会比“原始”版本更快吗? LINQ 不会神奇地消除该操作的时间复杂度。所以,是的,它看起来更好,但如果它被优化,它只是一点点。 这很好,因为我讨厌表达式语法。 这可能是我见过的最奇怪的事情。 “哦,让我们使用 LINQ,但不要使用内置的 C# 语法让我的代码对未来的开发人员更具可读性,让我们继续进行一长串函数调用!太棒了!” @Derrick Turk:确实如此,但是你不能使用像 yield return 或迭代器块这样的东西:)【参考方案2】:

之前:

// Init Movie
m_ImageArray = new Image[K_NB_IMAGE];

Stream l_ImageStream = null;
Bitmap l_Bitmap = null;

// get a reference to the current assembly
Assembly l_Assembly = Assembly.GetExecutingAssembly();

// get a list of resource names from the manifest
string[] l_ResourceName = l_Assembly.GetManifestResourceNames();

foreach (string l_Str in l_ResourceName)

    if (l_Str.EndsWith(".png"))
    
        // attach to stream to the resource in the manifest
        l_ImageStream = l_Assembly.GetManifestResourceStream(l_Str);
        if (!(null == l_ImageStream))
        
            // create a new bitmap from this stream and 
            // add it to the arraylist
            l_Bitmap = Bitmap.FromStream(l_ImageStream) as Bitmap;
            if (!(null == l_Bitmap))
            
                int l_Index = Convert.ToInt32(l_Str.Substring(l_Str.Length - 6, 2));
                l_Index -= 1;
                if (l_Index < 0) l_Index = 0;
                if (l_Index > K_NB_IMAGE) l_Index = K_NB_IMAGE;
                m_ImageArray[l_Index] = l_Bitmap;
            
            l_Bitmap = null;
            l_ImageStream.Close();
            l_ImageStream = null;
         // if
     // if
 // foreach

之后:

Assembly l_Assembly = Assembly.GetExecutingAssembly();

//Linq is the tops
m_ImageList = l_Assembly.GetManifestResourceNames()
    .Where(a => a.EndsWith(".png"))
    .OrderBy(b => b)
    .Select(c => l_Assembly.GetManifestResourceStream(c))
    .Where(d => d != null)  //ImageStream not null
    .Select(e => Bitmap.FromStream(e))
    .Where(f => f != null)  //Bitmap not null
    .ToList();

或者,或者(查询语法):

Assembly l_Assembly = Assembly.GetExecutingAssembly();

//Linq is the tops
m_ImageList = (
    from resource in l_Assembly.GetManifestResourceNames()
    where resource.EndsWith(".png")
    orderby resource
    let imageStream = l_Assembly.GetManifestResourceStream(resource)
    where imageStream != null
    let bitmap = Bitmap.FromStream(imageStream)
    where bitmap != null)
    .ToList();

【讨论】:

之前的示例更详细,但它具有可调试的优势。分析和修复复杂的 linq 语句可能很困难,因为它们对开发人员隐藏的太多。 @Phil,是也不是,你拥有的代码行数越多,要调试的也就越多!话虽如此,这就是为什么我更喜欢方法语法(After 示例中的第一个),因为它很容易在任何时候将方法链拼接成两个。 @Benjol:我从没想过这样做......所以你可以分解一个长的 linq 语句来查看每个方法返回什么,或者在你验证后将几个短的 linq 语句合并为一个他们会按照您的预期行事。这很有趣! 在之前的版本中,您明确关闭每个图像流。这会在 LINQ 版本的底层发生吗? @I. J,好问题。我认为这是我的代码中的一个错误。 Linq 做了很多神奇的事情,但我不认为它走得那么远。这实际上可能值得另一个问题......(也许在这里?:***.com/questions/1751153/…)【参考方案3】:

所以关于 LINQ 的真正重要的事情与 Linq to SQL 无关。这是关于它为 C# 语言本身带来的增强。

【讨论】:

【参考方案4】:

LINQ 不仅仅是一个 ORM 系统,正如 Jonathan 指出的那样,它为 C# 带来了许多函数式编程元素。它可以让你在常规 C# 代码中做很多“数据库-y”的事情。很难解释它的强大程度。考虑在通用框架中包含可靠、设计良好的通用数据结构(如列表、堆栈、字典/哈希等)在多大程度上改善了现代语言的开发状态。正是因为使用这些数据结构非常普遍,并且减少使用它们的智力开销是一个巨大的好处。 LINQ 不会做任何你自己做不到的事情,但它让很多操作变得更直接、更容易。

考虑从无序列表中删除重复项的历史悠久的示例。在像 C 或 C++ 这样的较低级别的语言中,您可能必须对列表进行排序并在删除重复项时在列表中维护两个索引。在具有散列的语言(Java、C#、javascript、Perl 等)中,您可以创建一个散列,其中键是唯一值,然后将键提取到新列表中。使用 LINQ,您可以这样做:

int[] data =  0, 1, 3, 3, 7, 8, 0, 9, 2, 1 ;

var uniqueData = data.GroupBy(i => i).Select(g => g.Key);

【讨论】:

甚至更好:data.Distinct();【参考方案5】:

因为 linq 确实是 sql 服装中的 monad,所以我在一个项目中使用它来使用 continuation monad 发出异步 Web 请求,并且证明它工作得非常好!

查看这些文章: http://www.aboutcode.net/2008/01/14/Async+WebRequest+Using+LINQ+Syntax.aspx http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx

从第一篇文章开始:

    var requests = new[] 
    
        WebRequest.Create("http://www.google.com/"),
        WebRequest.Create("http://www.yahoo.com/"),
        WebRequest.Create("http://channel9.msdn.com/")
    ;

    var pages = from request in requests
                select
                    from response in request.GetResponseAsync()
                    let stream = response.GetResponseStream()
                    from html in stream.ReadToEndAsync()
                    select new  html, response ;

    foreach (var page in pages)
    
        page(d =>
        
            Console.WriteLine(d.response.ResponseUri.ToString());
            Console.WriteLine(d.html.Substring(0, 40));
            Console.WriteLine();
        );
    

【讨论】:

【参考方案6】:

关键是 LINQ 将您的查询集成到您的主要编程语言中,允许您的 IDE 为您提供一些您原本不会拥有的功能(例如 Intellisense 和调试支持),并允许编译器键入 -检查你的 SQL 代码(这对于普通的字符串查询是不可能的)。

【讨论】:

但是为什么还要在 LINQ 中编写 sql 代码呢?你会如何调整它的性能?作为一个数据库人,我和提问者在一起。我只是不明白你为什么要从数据库的角度来做。我从 LINQ 看到的查询在我看来很臃肿。 如果您使用的是 ORM(any ORM),查询将会变得臃肿。如果你想要裸机,你应该通过 ADO.NET 使用 SQL(即使你主要使用 LINQ,这在代码的某些关键部分总是可能的)。 使用 linq 的另一个原因是,无论查询多么臃肿,SQL 引擎作者可能有一组较小的查询模式来进行内部调优。

以上是关于我错过了一些关于 LINQ 的东西吗?的主要内容,如果未能解决你的问题,请参考以下文章

一个可能的 Resharper 错误还是我只是错过了一些微妙的东西?

LINQ to SQL CompiledQuery 变慢

使用linq2sql的关系/外键?

小计划者 - 从哪里开始?

让 Snowpack 与 Babel 一起工作,“require is not defined”。我错过了需求转换吗?

圆形霍夫变换错过了圆圈