虽然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}");
}
使用 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}");
}
}
}
在查询语法中使用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("------------------------");
}
}
}
合并多个条件以提高性能。
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();
}
}
记住,这些是一般性的最佳实践,具体应用时还需要根据实际场景和需求进行调整。性能优化时应该进行实际测试,而不是盲目采用某种模式。
本文作者:rick
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!