LINQ to Objects #

一、LINQ to Objects概述 #

1.1 什么是LINQ to Objects #

LINQ to Objects是对实现了IEnumerable接口的集合进行查询。

1.2 特点 #

  • 内存中查询
  • 延迟执行
  • 链式调用
  • 类型安全

二、延迟执行 #

2.1 什么是延迟执行 #

csharp
var numbers = new List<int> { 1, 2, 3 };

var query = numbers.Where(n => n > 1);

numbers.Add(4);

foreach (var n in query)
{
    Console.WriteLine(n);
}

2.2 延迟执行的操作符 #

  • Where
  • Select
  • OrderBy
  • GroupBy
  • Take
  • Skip

2.3 重复执行 #

csharp
var numbers = new[] { 1, 2, 3 };
var query = numbers.Where(n => n > 1);

Console.WriteLine(query.Count());
Console.WriteLine(query.Sum());
Console.WriteLine(query.Average());

2.4 缓存结果 #

csharp
var numbers = new[] { 1, 2, 3 };
var query = numbers.Where(n => n > 1).ToList();

Console.WriteLine(query.Count);
Console.WriteLine(query.Count);

三、立即执行 #

3.1 什么是立即执行 #

csharp
var numbers = new[] { 1, 2, 3, 4, 5 };

List<int> list = numbers.Where(n => n > 2).ToList();
int[] array = numbers.Where(n => n > 2).ToArray();
int count = numbers.Count(n => n > 2);
int sum = numbers.Sum();

3.2 立即执行的操作符 #

  • ToList
  • ToArray
  • ToDictionary
  • ToLookup
  • Count
  • Sum
  • Average
  • First
  • Last
  • Any
  • All

四、查询优化 #

4.1 避免多次枚举 #

csharp
var numbers = Enumerable.Range(1, 1000000);

var filtered = numbers.Where(n => n % 2 == 0).ToList();

var count = filtered.Count;
var sum = filtered.Sum;
var average = filtered.Average;

4.2 使用合适的集合 #

csharp
var list = new List<int> { 1, 2, 3, 4, 5 };
var set = new HashSet<int> { 1, 2, 3, 4, 5 };

bool contains = set.Contains(3);

4.3 提前过滤 #

csharp
var numbers = Enumerable.Range(1, 1000000);

var result = numbers
    .Where(n => n % 2 == 0)
    .Where(n => n > 500000)
    .Take(100)
    .ToList();

五、常见场景 #

5.1 分页查询 #

csharp
public static IEnumerable<T> GetPage<T>(IEnumerable<T> source, int page, int pageSize)
{
    return source.Skip((page - 1) * pageSize).Take(pageSize);
}

var numbers = Enumerable.Range(1, 100);
var page1 = GetPage(numbers, 1, 10);
var page2 = GetPage(numbers, 2, 10);

5.2 去重 #

csharp
var numbers = new[] { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 };
var distinct = numbers.Distinct();

var people = new[] { new { Name = "张三", Age = 25 }, new { Name = "张三", Age = 30 } };
var distinctByName = people.DistinctBy(p => p.Name);

5.3 分组统计 #

csharp
var people = new[]
{
    new { Name = "张三", Age = 25, City = "北京" },
    new { Name = "李四", Age = 25, City = "上海" },
    new { Name = "王五", Age = 30, City = "北京" }
};

var stats = people
    .GroupBy(p => p.City)
    .Select(g => new { City = g.Key, Count = g.Count(), AvgAge = g.Average(p => p.Age) });

5.4 树形结构 #

csharp
public class TreeNode
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public List<TreeNode> Children { get; set; } = new();
}

public static List<TreeNode> BuildTree(IEnumerable<TreeNode> nodes)
{
    var nodeDict = nodes.ToDictionary(n => n.Id);
    var roots = new List<TreeNode>();
    
    foreach (var node in nodes)
    {
        if (node.ParentId == null)
        {
            roots.Add(node);
        }
        else if (nodeDict.TryGetValue(node.ParentId.Value, out var parent))
        {
            parent.Children.Add(node);
        }
    }
    
    return roots;
}

六、性能考虑 #

6.1 选择合适的操作符 #

csharp
var numbers = Enumerable.Range(1, 1000000);

var first = numbers.First(n => n > 500000);
var any = numbers.Any(n => n > 500000);

6.2 避免不必要的操作 #

csharp
var numbers = Enumerable.Range(1, 100);

var result = numbers
    .Where(n => n > 50)
    .Select(n => n * 2)
    .ToList();

var result = numbers
    .Select(n => n * 2)
    .Where(n => n > 100)
    .ToList();

七、总结 #

LINQ to Objects要点:

要点 说明
延迟执行 查询定义时不执行
立即执行 ToList/ToArray等
链式调用 流畅API
性能优化 避免多次枚举

下一步,让我们学习.NET生态!

最后更新:2026-03-26