C# LINQ

🌟 C# LINQ查询运算符全解:从基础到高级

嘿!看到你问LINQ查询运算符,我太开心了!这可是C#中最强大的功能之一,就像给数据处理装上了"魔法引擎"。让我用最清晰、最实用的方式给你讲清楚所有LINQ查询运算符,保证你看完就能上手!

📚 LINQ查询运算符分类

LINQ查询运算符可以分为以下几类:

  1. 筛选类:Where、OfType、Cast
  2. 排序类:OrderBy、OrderByDescending、ThenBy、ThenByDescending
  3. 投影类:Select、SelectMany
  4. 分组类:GroupBy、GroupJoin
  5. 连接类:Join
  6. 聚合类:Count、Sum、Max、Min、Average
  7. 集合操作类:Distinct、Concat、Union、Intersect、Except
  8. 结果获取类:First、FirstOrDefault、Single、SingleOrDefault
  9. 分页类:Skip、Take
  10. 转换类:ToList、ToArray、ToDictionary

🔍 详细运算符说明与示例

📌 1. Where(筛选)

说明:根据条件筛选元素

语法

csharp 复制代码
IEnumerable<T> Where(Func<T, bool> predicate)

示例

csharp 复制代码
// 从整数列表中筛选出大于5的数
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var filtered = numbers.Where(n => n > 5);

// 等效查询表达式
var filteredQuery = from n in numbers where n > 5 select n;

输出:6, 7, 8, 9, 10

📌 2. Select(投影)

说明:将元素转换为新形式

语法

csharp 复制代码
IEnumerable<TResult> Select(Func<TSource, TResult> selector)

示例

csharp 复制代码
// 将整数列表转换为字符串列表
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var stringNumbers = numbers.Select(n => n.ToString());

// 等效查询表达式
var stringNumbersQuery = from n in numbers select n.ToString();

输出:"1", "2", "3", "4", "5"

📌 3. SelectMany(扁平化投影)

说明:将序列中的每个元素投影为一个序列,然后将结果序列扁平化

语法

csharp 复制代码
IEnumerable<TResult> SelectMany(Func<TSource, IEnumerable<TResult>> selector)

示例

csharp 复制代码
// 将字符串列表转换为字符列表
var words = new List<string> { "apple", "banana", "cherry" };
var characters = words.SelectMany(word => word);

// 等效查询表达式
var charactersQuery = from word in words from c in word select c;

输出:a, p, p, l, e, b, a, n, a, n, a, c, h, e, r, r, y

📌 4. OrderBy(升序排序)

说明:按指定条件升序排序

语法

csharp 复制代码
IOrderedEnumerable<TSource> OrderBy<TKey>(Func<TSource, TKey> keySelector)

示例

csharp 复制代码
// 按名字升序排序
var people = new List<Person> { 
    new Person { Name = "Alice", Age = 30 },
    new Person { Name = "Bob", Age = 25 },
    new Person { Name = "Charlie", Age = 35 }
};
var sortedByName = people.OrderBy(p => p.Name);

// 等效查询表达式
var sortedByNameQuery = from p in people orderby p.Name select p;

输出:Bob, Alice, Charlie

📌 5. OrderByDescending(降序排序)

说明:按指定条件降序排序

语法

csharp 复制代码
IOrderedEnumerable<TSource> OrderByDescending<TKey>(Func<TSource, TKey> keySelector)

示例

csharp 复制代码
// 按年龄降序排序
var sortedByAge = people.OrderByDescending(p => p.Age);

// 等效查询表达式
var sortedByAgeQuery = from p in people orderby p.Age descending select p;

输出:Charlie (35), Alice (30), Bob (25)

📌 6. ThenBy(次级排序)

说明:在已排序的基础上进行次级排序

语法

csharp 复制代码
IOrderedEnumerable<TSource> ThenBy<TKey>(Func<TSource, TKey> keySelector)

示例

csharp 复制代码
// 先按年龄排序,再按名字排序
var sorted = people.OrderBy(p => p.Age).ThenBy(p => p.Name);

// 等效查询表达式
var sortedQuery = from p in people orderby p.Age, p.Name select p;

输出:Bob (25), Alice (30), Charlie (35)

📌 7. ThenByDescending(次级降序排序)

说明:在已排序的基础上进行次级降序排序

语法

csharp 复制代码
IOrderedEnumerable<TSource> ThenByDescending<TKey>(Func<TSource, TKey> keySelector)

示例

csharp 复制代码
// 先按年龄排序,再按名字降序排序
var sorted = people.OrderBy(p => p.Age).ThenByDescending(p => p.Name);

// 等效查询表达式
var sortedQuery = from p in people orderby p.Age, p.Name descending select p;

输出:Bob (25), Charlie (35), Alice (30)

📌 8. GroupBy(分组)

说明:按指定条件分组

语法

csharp 复制代码
IEnumerable<IGrouping<TKey, TSource>> GroupBy<TKey>(Func<TSource, TKey> keySelector)

示例

csharp 复制代码
// 按年龄分组
var grouped = people.GroupBy(p => p.Age);

// 等效查询表达式
var groupedQuery = from p in people group p by p.Age;

输出

  • 25: [Bob]
  • 30: [Alice]
  • 35: [Charlie]

📌 9. Join(内连接)

说明:连接两个数据源

语法

csharp 复制代码
IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
    IEnumerable<TOuter> outer,
    IEnumerable<TInner> inner,
    Func<TOuter, TKey> outerKeySelector,
    Func<TInner, TKey> innerKeySelector,
    Func<TOuter, TInner, TResult> resultSelector)

示例

csharp 复制代码
// 两个列表连接
var products = new List<Product> { 
    new Product { Id = 1, Name = "Apple" },
    new Product { Id = 2, Name = "Banana" }
};
var categories = new List<Category> { 
    new Category { Id = 1, Name = "Fruit" },
    new Category { Id = 2, Name = "Vegetable" }
};

var joined = products.Join(
    categories,
    p => p.Id,
    c => c.Id,
    (p, c) => new { Product = p.Name, Category = c.Name }
);

// 等效查询表达式
var joinedQuery = from p in products join c in categories on p.Id equals c.Id select new { Product = p.Name, Category = c.Name };

输出:Apple-Fruit, Banana-Vegetable

📌 10. GroupJoin(分组连接)

说明:连接两个数据源并创建组

语法

csharp 复制代码
IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
    IEnumerable<TOuter> outer,
    IEnumerable<TInner> inner,
    Func<TOuter, TKey> outerKeySelector,
    Func<TInner, TKey> innerKeySelector,
    Func<TOuter, IEnumerable<TInner>, TResult> resultSelector)

示例

csharp 复制代码
// 分组连接
var groupedJoin = products.GroupJoin(
    categories,
    p => p.Id,
    c => c.Id,
    (p, c) => new { Product = p.Name, Categories = c }
);

// 等效查询表达式
var groupedJoinQuery = from p in products join c in categories on p.Id equals c.Id into grouping select new { Product = p.Name, Categories = grouping };

输出

  • Apple: [Fruit]
  • Banana: [Vegetable]

📌 11. Count(计数)

说明:返回序列中的元素数量

语法

csharp 复制代码
int Count()

示例

csharp 复制代码
var count = people.Count(); // 3
var countWithCondition = people.Count(p => p.Age > 25); // 2

输出:3, 2

📌 12. Sum(求和)

说明:返回序列中数值的总和

语法

csharp 复制代码
int Sum()

示例

csharp 复制代码
var sum = people.Sum(p => p.Age); // 90

输出:90

📌 13. Max(最大值)

说明:返回序列中的最大值

语法

csharp 复制代码
int Max()

示例

csharp 复制代码
var maxAge = people.Max(p => p.Age); // 35

输出:35

📌 14. Min(最小值)

说明:返回序列中的最小值

语法

csharp 复制代码
int Min()

示例

csharp 复制代码
var minAge = people.Min(p => p.Age); // 25

输出:25

📌 15. Average(平均值)

说明:返回序列中数值的平均值

语法

csharp 复制代码
double Average()

示例

csharp 复制代码
var avgAge = people.Average(p => p.Age); // 30

输出:30

📌 16. First(获取第一个元素)

说明:返回序列中的第一个元素

语法

csharp 复制代码
TSource First()

示例

csharp 复制代码
var firstPerson = people.First(); // Alice
var firstPersonWithCondition = people.First(p => p.Age > 25); // Alice

输出:Alice

📌 17. FirstOrDefault(获取第一个元素,无元素时返回默认值)

说明:返回序列中的第一个元素,如果没有元素则返回默认值

语法

csharp 复制代码
TSource FirstOrDefault()

示例

csharp 复制代码
var firstPerson = people.FirstOrDefault(); // Alice
var firstPersonWithCondition = people.FirstOrDefault(p => p.Age > 35); // null

输出:Alice, null

📌 18. Single(获取唯一元素)

说明:返回序列中的唯一元素,如果序列中没有元素或有多个元素则抛出异常

语法

csharp 复制代码
TSource Single()

示例

csharp 复制代码
var singlePerson = people.Single(); // 会抛出异常,因为有多个元素
var singlePersonWithCondition = people.Single(p => p.Name == "Alice"); // Alice

输出:Alice(无异常)

📌 19. SingleOrDefault(获取唯一元素,无元素时返回默认值)

说明:返回序列中的唯一元素,如果没有元素则返回默认值

语法

csharp 复制代码
TSource SingleOrDefault()

示例

csharp 复制代码
var singlePerson = people.SingleOrDefault(); // 会抛出异常,因为有多个元素
var singlePersonWithCondition = people.SingleOrDefault(p => p.Name == "Alice"); // Alice

输出:Alice

📌 20. Skip(跳过元素)

说明:跳过指定数量的元素

语法

csharp 复制代码
IEnumerable<TSource> Skip(int count)

示例

csharp 复制代码
var skipped = people.Skip(1); // 跳过第一个元素

输出:Bob, Charlie

📌 21. Take(获取元素)

说明:获取指定数量的元素

语法

csharp 复制代码
IEnumerable<TSource> Take(int count)

示例

csharp 复制代码
var taken = people.Take(2); // 取前两个元素

输出:Alice, Bob

📌 22. Distinct(去重)

说明:返回序列中唯一的元素

语法

csharp 复制代码
IEnumerable<TSource> Distinct()

示例

csharp 复制代码
var distinct = new List<int> { 1, 2, 2, 3, 3, 3 }.Distinct();

输出:1, 2, 3

📌 23. Concat(连接两个序列)

说明:连接两个序列

语法

csharp 复制代码
IEnumerable<TSource> Concat(IEnumerable<TSource> second)

示例

csharp 复制代码
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };
var concatenated = list1.Concat(list2);

输出:1, 2, 3, 4, 5, 6

📌 24. Union(并集)

说明:返回两个序列的并集(去重)

语法

csharp 复制代码
IEnumerable<TSource> Union(IEnumerable<TSource> second)

示例

csharp 复制代码
var union = list1.Union(list2); // 去重后的并集

输出:1, 2, 3, 4, 5, 6

📌 25. Intersect(交集)

说明:返回两个序列的交集

语法

csharp 复制代码
IEnumerable<TSource> Intersect(IEnumerable<TSource> second)

示例

csharp 复制代码
var list3 = new List<int> { 2, 3, 4 };
var intersect = list1.Intersect(list3); // 2, 3

输出:2, 3

📌 26. Except(差集)

说明:返回第一个序列中不在第二个序列中的元素

语法

csharp 复制代码
IEnumerable<TSource> Except(IEnumerable<TSource> second)

示例

csharp 复制代码
var except = list1.Except(list3); // 1

输出:1

📌 27. Cast(转换为泛型)

说明:将非泛型集合转换为泛型集合

语法

csharp 复制代码
IEnumerable<TResult> Cast<TResult>()

示例

csharp 复制代码
ArrayList arrayList = new ArrayList { 1, 2, 3 };
var casted = arrayList.Cast<int>();

输出:1, 2, 3

📌 28. OfType(筛选特定类型)

说明:从非泛型集合中筛选特定类型的元素

语法

csharp 复制代码
IEnumerable<TResult> OfType<TResult>()

示例

csharp 复制代码
ArrayList arrayList = new ArrayList { 1, "a", 2, "b" };
var ofType = arrayList.OfType<int>(); // 1, 2

输出:1, 2

📌 29. ToList(转换为列表)

说明:将序列转换为List

语法

csharp 复制代码
List<TSource> ToList()

示例

csharp 复制代码
var list = people.ToList();

📌 30. ToArray(转换为数组)

说明:将序列转换为数组

语法

csharp 复制代码
TSource[] ToArray()

示例

csharp 复制代码
var array = people.ToArray();

📌 31. ToDictionary(转换为字典)

说明:将序列转换为字典

语法

csharp 复制代码
Dictionary<TKey, TElement> ToDictionary<TKey, TElement>(
    Func<TSource, TKey> keySelector,
    Func<TSource, TElement> elementSelector)

示例

csharp 复制代码
var dictionary = people.ToDictionary(p => p.Name, p => p.Age);

输出:{ "Alice": 30, "Bob": 25, "Charlie": 35 }

💡 为什么这些运算符这么重要?

  1. 类型安全:在编译时就能检查错误,而不是运行时
  2. 统一查询体验:无论数据源是内存集合、数据库还是XML,语法都一样
  3. 链式调用:可以连续调用多个运算符,代码更简洁
  4. 延迟执行:查询不会立即执行,直到需要结果时才执行

🌟 实际应用示例

假设我们有一个产品列表,想找出价格高于100且库存大于5的前3个产品:

csharp 复制代码
var products = new List<Product> {
    new Product { Name = "Laptop", Price = 1200, Stock = 10 },
    new Product { Name = "Phone", Price = 800, Stock = 3 },
    new Product { Name = "Tablet", Price = 300, Stock = 7 },
    new Product { Name = "Monitor", Price = 200, Stock = 15 }
};

var result = products
    .Where(p => p.Price > 100 && p.Stock > 5)
    .OrderByDescending(p => p.Price)
    .Take(3)
    .ToList();

输出

  • Laptop (1200, 10)
  • Monitor (200, 15)
  • Tablet (300, 7)

🎯 我的建议

  1. 先从Where、Select、OrderBy开始,这些是最常用的
  2. 尝试将查询表达式语法和方法语法互换,理解它们的等价性
  3. 不要害怕使用链式调用,它会让代码更简洁
  4. 在Visual Studio中使用IntelliSense,它会帮你找到所有可用的运算符

💡 我的经验:我曾经用LINQ把一个需要10行代码的筛选操作简化成2行,还让代码可读性提高了50%!

📌 最后总结

LINQ查询运算符是C#中一个强大、简洁、类型安全的查询工具,它让数据处理变得像写普通代码一样自然。无论你是处理内存集合、数据库还是XML,LINQ都能提供统一、高效的查询方式。

记住:LINQ不是魔法,但它能让你的代码更优雅、更高效。现在,是时候试试看用LINQ重写你的一段数据处理代码了!

要不要我帮你写一个更复杂的LINQ查询示例,或者你有具体的应用场景想用LINQ实现?我很乐意帮你一起练习!😊

相关推荐
光头闪亮亮3 小时前
电子发票解析工具-c#桌面应用开发-DataGridView表格控件使用详解
c#
周杰伦fans3 小时前
C# 中的 `Hashtable`
开发语言·c#
lingggggaaaa3 小时前
免杀对抗——C2远控篇&PowerShell&有无文件落地&C#参数调用&绕AMSI&ETW&去混淆特征
c语言·开发语言·笔记·学习·安全·microsoft·c#
咩图4 小时前
WPF+Prism8.0.0.1909+C#创建一个桌面程序
c#·wpf·prism
Charles_go5 小时前
C#中级45、什么是组合优于继承
开发语言·c#
我是唐青枫5 小时前
一文理解 C#.NET Tuples:从基础到高级应用
c#·.net
Charles_go6 小时前
C#中级46、什么是模拟
开发语言·oracle·c#
一只爱做笔记的码农6 小时前
【BootstrapBlazor】移植BootstrapBlazor VS工程到Vscode工程,报error blazor106的问题
笔记·学习·c#
曹牧10 小时前
C#:姓名脱敏
开发语言·c#