编辑
2025-02-10
C# 应用
00
请注意,本文编写于 85 天前,最后修改于 85 天前,其中某些信息可能已经过时。

目录

优先使用方法语法而不是查询语法
合理使用 var 关键字
理解并利用延迟执行
合理使用即时执行方法
优化性能检查
安全的元素访问
高效的投影
使用let子句优化计算
条件组合优化
多级排序
分组操作
连接操作
最佳实践总结

优先使用方法语法而不是查询语法

虽然LINQ提供了两种语法风格,但方法语法通常更简洁和直观。

C#
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // 查询语法 var result1 = from num in numbers where num % 2 == 0 select num; // 方法语法(推荐) var result2 = numbers.Where(num => num % 2 == 0); // 复杂查询示例 var result3 = numbers.Where(n => n > 10) .OrderBy(n => n) .Select(n => new { Number = n, Square = n * n }); // 输出结果 Console.WriteLine("查询语法结果:"); foreach (var num in result1) { Console.WriteLine(num); } Console.WriteLine("方法语法结果:"); foreach (var num in result2) { Console.WriteLine(num); } Console.WriteLine("复杂查询结果:"); foreach (var item in result3) { Console.WriteLine($"Number: {item.Number}, Square: {item.Square}"); }

image.png

合理使用 var 关键字

使用 var 可以让代码更简洁,特别是处理复杂的LINQ查询结果时。

C#
// 定义Customer和Order类 public class Customer { public int Id { get; set; } public string Name { get; set; } } public class Order { public int Id { get; set; } public int CustomerId { get; set; } public decimal Amount { get; set; } } internal class Program { static void Main(string[] args) { // 声明一个数字列表用于演示 List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 推荐做法 var evenNumbers = numbers.Where(n => n % 2 == 0); // 创建示例数据 var customers = new List<Customer>(); var orders = new List<Order>(); // 使用LINQ Join查询 var customerOrders = customers .Join(orders, c => c.Id, o => o.CustomerId, (c, o) => new { Customer = c, Order = o }); // 当类型明显时,也可以显式声明 List<int> simpleList = numbers.Where(n => n < 10).ToList(); } }

理解并利用延迟执行

LINQ查询默认采用延迟执行策略,只有在实际需要结果时才会执行查询。

C#
// 查询定义(不会立即执行) var query = numbers .Where(n => n > 10) .Select(n => new { Value = n, Double = n * 2 }); // 查询执行(遍历时才真正执行) foreach (var item in query) { Console.WriteLine($"Value: {item.Value}, Double: {item.Double}"); } // 多次使用同一查询 var cachedResult = query.ToList(); // 执行一次并缓存结果

合理使用即时执行方法

知道何时强制执行查询是很重要的。

C#
// 立即执行并缓存结果 var list = numbers.Where(n => n > 1000).ToList(); var array = numbers.Where(n => n > 1000).ToArray(); var count = numbers.Count(n => n > 1000); var first = numbers.FirstOrDefault(n => n > 1000);

优化性能检查

使用最适合场景的方法来提高性能。

C#
// 不推荐 if (numbers.Count(n => n > 10) > 0) { } // 推荐 if (numbers.Any(n => n > 10)) { } // 查找元素 // 不推荐 var first1 = numbers.Where(n => n > 10).First(); // 推荐 var first2 = numbers.First(n => n > 10);

安全的元素访问

使用带有默认值的方法来避免异常。

C#
// 可能抛出异常 // var first = numbers.First(n => n > 1000000); // 安全的访问方式 var first = numbers.FirstOrDefault(n => n > 1000000); var single = numbers.SingleOrDefault(n => n == 5); // 带默认值的安全访问 var firstWithDefault = numbers .FirstOrDefault(n => n > 1000000, -1); // .NET 6+

高效的投影

正确使用Select进行数据转换。

C#
// 定义Person类 public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int BirthYear { get; set; } } // 定义PersonDto类 public class PersonDto { public string FullName { get; set; } public int Age { get; set; } public bool IsAdult { get; set; } } internal class Program { static void Main(string[] args) { // 创建示例数据 var persons = new List<Person> { new Person { FirstName = "John", LastName = "Doe", BirthYear = 1990 }, new Person { FirstName = "Jane", LastName = "Smith", BirthYear = 2010 }, new Person { FirstName = "Mike", LastName = "Johnson", BirthYear = 1985 } }; // 基本投影 - 只获取姓名 var names = persons.Select(p => p.FirstName); // 复杂投影 - 转换为DTO对象 var personDtos = persons.Select(p => new PersonDto { FullName = $"{p.FirstName} {p.LastName}", Age = DateTime.Now.Year - p.BirthYear, IsAdult = DateTime.Now.Year - p.BirthYear >= 18 }); // 输出结果示例 Console.WriteLine("基本投影结果:"); foreach (var name in names) { Console.WriteLine(name); } Console.WriteLine("\n复杂投影结果:"); foreach (var dto in personDtos) { Console.WriteLine($"姓名: {dto.FullName}, 年龄: {dto.Age}, 是否成年: {dto.IsAdult}"); } } }

image.png

使用let子句优化计算

在查询语法中使用let可以提高可读性和性能。

C#
// 定义Person类 public class Person { public string Name { get; set; } public int BirthYear { get; set; } public override string ToString() { return $"Name: {Name}, Birth Year: {BirthYear}"; } } internal class Program { static void Main(string[] args) { // 创建示例数据 var persons = new List<Person> { new Person { Name = "John Doe", BirthYear = 1990 }, new Person { Name = "Jane Smith", BirthYear = 2010 }, new Person { Name = "Mike Johnson", BirthYear = 1985 }, new Person { Name = "Sarah Williams", BirthYear = 2005 } }; // 使用LINQ查询语法,包含let子句 var query = from person in persons let age = DateTime.Now.Year - person.BirthYear let isAdult = age >= 18 where isAdult select new { person.Name, Age = age, CanVote = age >= 18 }; // 输出结果 Console.WriteLine("成年人信息:"); foreach (var result in query) { Console.WriteLine($"姓名: {result.Name}"); Console.WriteLine($"年龄: {result.Age}"); Console.WriteLine($"可以投票: {result.CanVote}"); Console.WriteLine("------------------------"); } // 等效的方法语法(Method Syntax)版本 var methodSyntaxQuery = persons .Select(person => new { Person = person, Age = DateTime.Now.Year - person.BirthYear }) .Where(x => x.Age >= 18) .Select(x => new { x.Person.Name, Age = x.Age, CanVote = x.Age >= 18 }); // 输出方法语法版本的结果 Console.WriteLine("\n使用方法语法的结果:"); foreach (var result in methodSyntaxQuery) { Console.WriteLine($"姓名: {result.Name}"); Console.WriteLine($"年龄: {result.Age}"); Console.WriteLine($"可以投票: {result.CanVote}"); Console.WriteLine("------------------------"); } } }

image.png

条件组合优化

合并多个条件以提高性能。

C#
// 不推荐 var result1 = numbers .Where(n => n > 10) .Where(n => n % 2 == 0) .Where(n => n < 100); // 推荐 var result2 = numbers .Where(n => n > 10 && n % 2 == 0 && n < 100);

多级排序

使用OrderBy和ThenBy进行多条件排序。

C#
var sortedPersons = persons .OrderBy(p => p.LastName) .ThenBy(p => p.FirstName) .ThenByDescending(p => p.Age);

分组操作

使用GroupBy进行高效的数据分组。

C#
var groupedResult = persons .GroupBy(p => p.City) .Select(g => new { City = g.Key, Count = g.Count(), AverageAge = g.Average(p => p.Age),Persons = g.ToList() });

连接操作

使用Join和GroupJoin进行数据关联。

C#
public class Customer { public int CustomerId { get; set; } public string Name { get; set; } } public class Order { public int OrderId { get; set; } public int CustomerId { get; set; } public DateTime OrderDate { get; set; } public decimal Amount { get; set; } } public static void Main() { // 创建测试数据 var customers = new List<Customer> { new Customer { CustomerId = 1, Name = "John" }, new Customer { CustomerId = 2, Name = "Jane" }, new Customer { CustomerId = 3, Name = "Bob" }, new Customer { CustomerId = 4, Name = "Alice" } }; var orders = new List<Order> { new Order { OrderId = 1, CustomerId = 1, OrderDate = DateTime.Parse("2023-01-01"), Amount = 100m }, new Order { OrderId = 2, CustomerId = 1, OrderDate = DateTime.Parse("2023-02-01"), Amount = 200m }, new Order { OrderId = 3, CustomerId = 2, OrderDate = DateTime.Parse("2023-01-15"), Amount = 150m }, new Order { OrderId = 4, CustomerId = 1, OrderDate = DateTime.Parse("2023-03-01"), Amount = 300m } }; // 简单连接 var simpleJoin = customers.Join( orders, customer => customer.CustomerId, // 外部序列键选择器 order => order.CustomerId, // 内部序列键选择器 (customer, order) => new // 结果选择器 { CustomerName = customer.Name, OrderId = order.OrderId, OrderDate = order.OrderDate, Amount = order.Amount }); // 输出简单连接结果 Console.WriteLine("Simple Join Results:"); foreach (var item in simpleJoin) { Console.WriteLine($"Customer: {item.CustomerName}, Order ID: {item.OrderId}, " + $"Date: {item.OrderDate.ToShortDateString()}, Amount: ${item.Amount}"); } // 分组连接 var groupJoin = customers.GroupJoin( orders, customer => customer.CustomerId, // 外部序列键选择器 order => order.CustomerId, // 内部序列键选择器 (customer, customerOrders) => new // 结果选择器 { CustomerName = customer.Name, OrderCount = customerOrders.Count(), TotalAmount = customerOrders.Sum(o => o.Amount), Orders = customerOrders.ToList() }); // 输出分组连接结果 Console.WriteLine("\nGroup Join Results:"); foreach (var item in groupJoin) { Console.WriteLine($"Customer: {item.CustomerName}"); Console.WriteLine($"Order Count: {item.OrderCount}"); Console.WriteLine($"Total Amount: ${item.TotalAmount}"); Console.WriteLine("Orders:"); foreach (var order in item.Orders) { Console.WriteLine($" Order ID: {order.OrderId}, " + $"Date: {order.OrderDate.ToShortDateString()}, " + $"Amount: ${order.Amount}"); } Console.WriteLine(); } }

image.png

最佳实践总结

  1. 优先使用方法语法,除非查询语法能提供更好的可读性
  2. 理解延迟执行的概念,合理使用ToList()或ToArray()
  3. 使用适当的方法避免性能问题(Any vs Count)
  4. 选择安全的元素访问方法(FirstOrDefault vs First)
  5. 合理使用投影和分组来组织数据
  6. 优化查询条件,避免多余的链式调用
  7. 使用适当的排序方法进行多级排序
  8. 根据实际需求选择合适的连接操作

记住,这些是一般性的最佳实践,具体应用时还需要根据实际场景和需求进行调整。性能优化时应该进行实际测试,而不是盲目采用某种模式。

本文作者:rick

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!