在 C# LINQ 中,Select 是一个投影(Projection)操作符。它的核心作用是转换。
简单来说,Select 允许你遍历一个集合,并对集合中的每一个元素进行处理,然后返回一个新的集合。
List<A>,输出集合可以是 List<B>。SELECT column_name FROM table。这是最常见的场景。你有一个包含复杂对象的列表,但你只需要其中的某一列数据。
class User { public string Name { get; set; } public string Email { get; set; } } List<User> users = new List<User> { new User { Name = "张三", Email = "zhang@test.com" }, new User { Name = "李四", Email = "li@test.com" } }; // 这里的 u 代表每一个 User 对象 // u.Email 表示我们只想要 Email 属性 IEnumerable<string> emails = users.Select(u => u.Email); // 结果:["zhang@test.com", "li@test.com"]
你可以在 Select 中进行运算,把数据变成另一种形式。
List<int> numbers = new List<int> { 1, 2, 3, 4 }; // 对每一个数字 n,返回 n * n var squares = numbers.Select(n => n * n); // 结果:[1, 4, 9, 16]
当你需要从一个大对象中提取多个属性,并组合成一个新的、临时的对象时,这非常有用。
class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public string Description { get; set; } // 不需要这个 } List<Product> products = GetProducts(); // 创建一个新的匿名对象,只包含 Id 和 Name var simpleProducts = products.Select(p => new { p.Id, p.Name, DisplayName = p.Name + " (特价)" // 甚至可以创建新字段 }); foreach(var item in simpleProducts) { // 此时 item 是一个匿名类型 Console.WriteLine($"{item.Id}: {item.DisplayName}"); }
Select 有一个重载版本,可以让你同时访问元素和它的索引(位置)。
语法:(element, index) ⇒ …
List<string> racers = new List<string> { "刘翔", "博尔特", "苏炳添" }; // x 是名字,i 是索引(从0开始) var results = racers.Select((x, i) => $"第 {i + 1} 名是: {x}"); // 结果: // "第 1 名是: 刘翔" // "第 2 名是: 博尔特" // "第 3 名是: 苏炳添"
虽然上面的例子都是基于方法语法 (Method Syntax),但 Select 在查询语法 (Query Syntax) 中同样重要。
| 语法类型 | 代码示例 | 说明 |
|---|---|---|
| 方法语法 | users.Select(u ⇒ u.Name) | 使用 Lambda 表达式,更简洁,支持所有操作符 |
| 查询语法 | from u in users select u.Name | 看起来更像 SQL,可读性在复杂查询时较好 |
查询语法示例:
var names = from u in users select u.Name;
假设你有一箱橙子(原始集合):
Select(橙子 ⇒ 橙子汁)Select(橙子 ⇒ 橙子.产地)