CodeGym /课程 /C# SELF /LINQ简介及其优势

LINQ简介及其优势

C# SELF
第 31 级 , 课程 0
可用

1. 入门

想象一下,你走进图书馆,需要找所有2020年以后出版的编程书,并按作者名排序。你肯定不会一个书架一个书架地翻吧?你会找个懂行的图书管理员,帮你快速搞定。

LINQLanguage Integrated Query,意思就是“集成到语言里的查询”)—— 就是我们的“聪明图书管理员”,是C#里的“SQL引擎”(也就是写数据查询的工具)!

LINQ当成一种语言,它让你描述你想从数据里拿到什么,而不是怎么拿。你不用再说:“先拿第一个元素,判断条件,符合就加到新列表,然后下一个……”,你只要说:“给我所有价格大于1000的商品”。C#自己会想办法高效地搞定。

LINQ的核心思想:给所有实现了IEnumerable<T>接口的数据源,提供统一的查询语法。超棒的是,List<T>、数组、HashSet<T>这些都实现了IEnumerable<T>。如果你的数据在数据库里,像Entity Framework这样的库还能把LINQ查询转成真正的SQL!

LINQ在C#里已经有10多年历史了。它的出现,彻底改变了.NET里处理数据的方式。LINQ之前,开发者得写一堆模板代码来过滤、排序、转换集合,或者直接写SQL字符串,但这些字符串编译器根本不管,运行时才会报错。LINQ把“查询”这个概念直接带进了编程语言,让它们类型安全、可读性更强。

很多人觉得LINQ是C#自从有了泛型(Generics)以来最牛的创新之一。

2. LINQ的优点:为什么大家都爱它?

代码简洁又好读:比如你要过滤出价格大于1000的商品,以前得写好几行代码。用LINQ一句话搞定。代码越少,出错的机会越少,读起来也更顺。代码看起来就像自然语言一样。
程序员段子:“我写的代码越少,能塞进去的bug也越少。”LINQ就是帮你做到这点!

强大又灵活:LINQ有超多操作:过滤(Where)、投影(Select)、排序(OrderBy)、分组(GroupBy)、聚合(SumAverage)、连接(Join)等等。你可以把这些操作组合起来,轻松搞定复杂的数据处理。

类型安全:这个超重要!你写SQL字符串时,编译器啥都不知道。你要是把列名写错了,只有程序跑起来才会报错。LINQ不一样,C#编译器会在编译时就检查你的查询。如果你查了Product对象里没有的字段,编译器立马报错。就像有个专属校对员,帮你提前抓住所有拼写错误。

和语言深度集成:LINQ查询不是啥“魔法字符串”,它就是C#的正规语法,用你熟悉的lambda表达式,操作你熟悉的数据类型。上手LINQ特别顺滑。

延迟执行(Deferred Execution):这是LINQ最酷、也最难但很重要的概念之一。意思是LINQ查询写出来后不会立刻执行,而是等你真的要结果时(比如用foreach遍历)才执行。这样可以优化查询,尤其是处理大数据量时。我们在第166讲会详细聊这个。现在你只要记住:LINQ很聪明,不会做多余的事。

通用又可扩展:LINQ不只是内存里的列表。LINQ有各种“Provider”:

  • LINQ to Objects:操作内存里的集合(List<T>、数组等)。
  • LINQ to SQL / Entity Framework Core:操作SQL数据库(LINQ查询会转成SQL)。
  • LINQ to XML:操作XML文档。
  • 还有很多别的。
    这意味着,只要你会LINQ,啥数据源都能用同一套查询逻辑搞定。

3. “老派”处理集合的问题

LINQ出来之前,C#里处理集合的代码大概长这样:


var products = new List<Product> { /* ... */ };

var expensive = new List<Product>();
foreach (var prod in products)
{
    if (prod.Price > 100)
        expensive.Add(prod);
}

expensive.Sort((a, b) => a.Price.CompareTo(b.Price));

foreach (var item in expensive)
    Console.WriteLine(item.Name);

这种写法很常见:先手动过滤,再排序——还得建个中间列表。逻辑越多,代码越多,变量越多,出错也越多。就像在家具厂手工拼家具:零件有了,装起来累死人。

循环国的爱丽丝

想象你有个超大的用户列表,只想要那些年龄大于18、住在霓虹城的用户名字,按字母排序,取前三个。你得写嵌套循环、条件、排序、辅助列表……或者直接用LINQ。

4. LINQ查询长啥样?简单例子

LINQ有两种主要语法:

  • Method Syntax(方法链式写法)
  • Query Syntax(类似SQL的写法)

现在项目里基本都用Method Syntax。比如我们这个小应用:


var expensive = products
    .Where(p => p.Price > 100)
    .OrderBy(p => p.Price)
    .Select(p => p.Name)
    .Take(3);

foreach (var name in expensive)
    Console.WriteLine(name);

一目了然:过滤、排序、选字段、限制数量。代码最少,意思最清楚。

同样的用Query Syntax写


var expensive = from p in products
                where p.Price > 100
                orderby p.Price
                select p.Name;

foreach (var name in expensive.Take(3))
    Console.WriteLine(name);

两种写法结果一样——你喜欢哪个用哪个(不过method写法更常见)。

5. LINQ架构:底层怎么跑的?

LINQ能操作所有实现了IEnumerable<T>(或者IQueryable<T>,后面会讲)的集合。

LINQ的主要组成

组件 简要说明
LINQ扩展类 静态方法(
Where
Select
OrderBy
等)都在
System.Linq.Enumerable
类里
委托 最常用
Func<T, TResult>
Predicate<T>
延迟执行 查询只有在第一次遍历(比如
foreach
)时才会真正执行
Query Provider (LINQ to SQL、LINQ to Entities用)——把方法链转成SQL等查询

可视化流程图


集合(List<Product>、T[]、...) 
      │
      ▼
LINQ方法(Where、OrderBy、Select...)
      │
      ▼
查询(IEnumerable<T>) 
      │
      ▼
真正执行(foreach、ToList、Count、...)

6. 例子:一步步拆解LINQ链式写法

回到我们的迷你应用,Product类:


// 商品类
class Product
{
    public string Name { get; set; }
    public double Price { get; set; }
}

商品列表如下:


var products = new List<Product>
{
    new Product { Name = "奶酪", Price = 250.5 },
    new Product { Name = "面包", Price = 30 },
    new Product { Name = "牛奶", Price = 80 },
    new Product { Name = "咖啡", Price = 330 },
    new Product { Name = "黄油", Price = 140 }
};

假设我们的任务是:把所有价格大于100欧元的商品名按价格排序输出

老方法


var filtered = new List<Product>();
foreach (var p in products)
{
    if (p.Price > 100)
        filtered.Add(p);
}

filtered.Sort((a, b) => a.Price.CompareTo(b.Price));

foreach (var p in filtered)
    Console.WriteLine(p.Name);

LINQ方法


var expensive = products
    .Where(p => p.Price > 100)
    .OrderBy(p => p.Price)
    .Select(p => p.Name);

foreach (var name in expensive)
    Console.WriteLine(name);

第一行就把需求说清楚了:“过滤出Price > 100,按价格排序,选名字”。

7. 常用LINQ操作和“老派”写法对比

操作 老派逻辑 LINQ
过滤 foreach + if + Add
Where
投影(选字段) foreach + Add(field)
Select
排序 Sort(comparer)
OrderBy
OrderByDescending
去重 foreach + contains + Add
Distinct
计数 foreach + counter++
Count
Count(predicate)
条件判断 foreach + if
Any
All
找第一个/最后一个 foreach + if + break
First
Last
FirstOrDefault
限制数量 foreach + 计数器 + break
Take
Skip

8. 实战:把LINQ加进你的应用

拿我们的基础代码(Product列表),用LINQ实现几个常用操作。

过滤和排序


// 选出价格低于200欧元的商品并按名字排序
var cheapProducts = products
    .Where(p => p.Price < 200)
    .OrderBy(p => p.Name);

foreach (var p in cheapProducts)
    Console.WriteLine($"{p.Name}: {p.Price}欧元");

集合转换(投影)


// 得到价格列表(double)
var prices = products.Select(p => p.Price);

foreach (var price in prices)
    Console.WriteLine(price);

找第一个符合条件的元素


// 第一个名字以“咖”开头的商品
var firstK = products.FirstOrDefault(p => p.Name.StartsWith("咖"));
Console.WriteLine(firstK?.Name ?? "没找到");

统计价格大于100欧元的商品数量


int count = products.Count(p => p.Price > 100);
Console.WriteLine($"这样的商品有:{count}个。");

从这节课开始,我们会大量用LINQ来处理集合、过滤、选数据、聚合等等。LINQ的新方法和新特性(包括.NET 9的新玩意儿!)我们后面会详细讲,现在就大胆试试简单查询,感受一下LINQ的威力吧!

2
任务
C# SELF, 第 31 级, 课程 0
已锁定
从数组中过滤数字
从数组中过滤数字
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION