LINQ、Lazy 和 C#:您需要了解的有关惰性求值查询的知识

发布日期:2026-07-14 01:54:04   来源 : 杭州电子商务研究院    浏览量 :9
杭州电子商务研究院 发布日期:2026-07-14 01:54:04  
9

介绍

LINQ是 Language Integrated Query 的缩写,于 2007 年在 .NET Framework 3.5 版中引入。其核心概念是扩展框架(以及 C# 语言)以提供查询表达功能。我们将这些功能分为两类:查询语法方法语法。前者更像是 SQL 查询,用于筛选出符合特定条件的不同数据,而后者则是通过类似于 SQL 查询关键字的方法调用来完成的。它允许您处理不同类型的数据,例如 SQL 数据库、XML 文档和来自 Web 服务的响应。

在本指南中,我们将看到这两种语法的示例,并讨论延迟执行和惰性求值和急切求值。

查询和方法语法

这是查询语法的一个小演示。假设我们有一个服务器及其功能的列表。

      IList<string> serverList = new List<string>() { 
    "Parabellum - Domain Controller",
    "Prostetic - DNS",
    "Spooky - Domain Controller",
    "Scar - DHCP" ,
    "BigBoy - Web Server" 
};
    

假设我们想查询列表中的所有域控制器。

利用查询语法方法,我们可以按如下方式实现这一点。

      var DCS = from s in serverList
            where s.Contains("Domain Controller") 
            select s;
    

使用方法语法,这就是解决问题的方法。

      var DCS = serverList.Where(s => s.Contains("Domain Controller"));
    

在这两种情况下,DCS变量都保存着一个包含两个匹配服务器的列表。

延迟执行

为了深入了解 LINQ 及其其他优势,我们需要了解延迟执行。在大多数情况下,在编译期间,LINQ 表达式会在特定数据集上进行评估,并使用筛选值初始化变量。通过实现延迟执行,我们可以节省宝贵的 CPU 和 RAM 资源,因为我们不必评估特定表达式或延迟评估直到实际需要实现值。在两种情况下,这非常有用。第一种是当您的应用程序正在处理多个 GB 甚至 TB 的数据时,第二种是当您将多个查询链接在一起导致对数据集的不同操作时。

屈服

为了加深对延迟执行的理解,我们需要介绍关键字yield。此关键字是在 C# 2.0 版中引入的。它对于惰性求值至关重要,并可提高 LINQ 查询的性能。关键字yield是上下文相关的,这意味着它可以用作变量名而不会出现任何问题。让我们创建一个使用yield遍历服务器的小应用程序。

      using System;
using System.Collections.Generic;

namespace Pluralsight
{
    public class Server {
        string _name;
        string _function;
        public string Name {
            get { return _name; }
            set { _name = value; }
        }
        public string Function {
            get { return _function; }
            set { _function = value; }
        }
        public Server(string Name, string Function) {
            _name = Name;
            _function = Function;
        }
    }
    public class Yielder
    {
        public static IEnumerable<Server> ServerDB()
        {
            Server[] servers = new Server[]
                {
                new Server("Parabellum","Domain Controller"),
                new Server("Pluck","DNS Server"),
                new Server("Pilgrim","Web Server"),
                new Server("Spark","Firewall Server"),
                };
            foreach(Server s in servers)
            {
                yield return s;
            }
        }
        public static void Main()
        {
            
            foreach(Server s in ServerDB())
            {
                Console.WriteLine($"Name: {s.Name}, Function: {s.Function}");
            }
            
            Console.ReadKey();            
        }
    }
}
    

这将产生以下输出。

      Name: Parabellum, Function: Domain Controller
Name: Pluck, Function: DNS Server
Name: Pilgrim, Function: Web Server
Name: Spark, Function: Firewall Server
    

这里的关键是yield 它允许我们迭代Server[]列表的每个元素。它不会一次返回整个列表,从而节省内存并提高性能。这也是延迟执行的一个例子,因为foreach循环逐个提取项目,并对其进行迭代。如果我们愿意,我们可以通过在yield return s;部分之后放置以下行来尝试一下

      Console.WriteLine($"Sending {s.Name}");
    

这将按以下方式修改输出。

      Name: Parabellum, Function: Domain Controller
Sending Parabellum
Name: Pluck, Function: DNS Server
Sending Pluck
Name: Pilgrim, Function: Web Server
Sending Pilgrim
Name: Spark, Function: Firewall Server
Sending Spark
    

请注意, Sending...是如何出现在数组中每个元素后面的。

懒惰与渴望

使用惰性求值意味着每次调用迭代器时,仅处理源集合的单个元素。迭代器可以是自定义类foreachwhile循环,具体取决于您的上下文。

与此相反的通常是急切求值。这意味着第一次调用迭代器将返回整个集合或数据集。

结论

在本指南中,我们了解了 LINQ 如何彻底改变程序员处理不同数据集和与不同数据源交互的方式。我们看到了一些查询和方法语法的示例,并了解了惰性求值和急切求值之间的区别。希望本指南对您有所帮助,感谢您阅读本指南!

以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据