跳转到内容

C Sharp LINQ 过滤

来自代码酷

C# LINQ 过滤[编辑 | 编辑源代码]

LINQ(Language Integrated Query)是C#中用于查询数据的强大工具,而过滤是LINQ中最常用的操作之一。通过过滤,可以从数据集合中筛选出符合特定条件的元素。本教程将详细介绍LINQ过滤的概念、语法、实际应用以及相关技巧。

介绍[编辑 | 编辑源代码]

LINQ过滤操作允许开发者使用简洁的语法从数据源(如数组、集合、数据库等)中提取满足特定条件的元素。最常见的过滤方法是使用Where子句,它接受一个谓词(返回布尔值的函数)作为参数,并返回所有满足该谓词的元素。

LINQ过滤可以应用于任何实现了IEnumerable<T>IQueryable<T>接口的数据源,包括:

  • 内存中的集合(如List、Array)
  • 数据库(通过Entity Framework)
  • XML文档
  • 其他自定义数据源

基本语法[编辑 | 编辑源代码]

LINQ提供两种语法形式来执行过滤操作:查询语法方法语法

查询语法[编辑 | 编辑源代码]

查询语法类似于SQL,使用`where`关键字进行过滤:

from item in collection
where condition
select item;

方法语法[编辑 | 编辑源代码]

方法语法使用扩展方法,主要通过`Where()`方法:

collection.Where(item => condition);

两种语法在功能上是等价的,编译器会将查询语法转换为方法语法。

代码示例[编辑 | 编辑源代码]

示例1:基本过滤[编辑 | 编辑源代码]

以下示例演示如何从一个整数列表中筛选出偶数:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// 查询语法
var evenNumbersQuery = from num in numbers
                       where num % 2 == 0
                       select num;

// 方法语法
var evenNumbersMethod = numbers.Where(num => num % 2 == 0);

// 输出结果
Console.WriteLine("偶数:");
foreach (var num in evenNumbersMethod)
{
    Console.WriteLine(num);
}

输出:

偶数:
2
4
6
8
10

示例2:复杂条件过滤[编辑 | 编辑源代码]

可以组合多个条件进行更复杂的过滤:

List<string> fruits = new List<string> 
{ 
    "Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig", "Grape" 
};

// 长度大于3且包含字母'a'的水果
var filteredFruits = fruits.Where(f => f.Length > 3 && f.ToLower().Contains('a'));

foreach (var fruit in filteredFruits)
{
    Console.WriteLine(fruit);
}

输出:

Banana
Cherry
Elderberry
Grape

实际应用案例[编辑 | 编辑源代码]

案例1:电子商务产品过滤[编辑 | 编辑源代码]

假设有一个电子商务网站,需要根据用户选择的条件过滤产品:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
    public int Stock { get; set; }
}

List<Product> products = new List<Product>
{
    new Product { Id = 1, Name = "Laptop", Price = 999.99m, Category = "Electronics", Stock = 10 },
    new Product { Id = 2, Name = "Smartphone", Price = 699.99m, Category = "Electronics", Stock = 15 },
    new Product { Id = 3, Name = "Desk Chair", Price = 199.99m, Category = "Furniture", Stock = 5 },
    new Product { Id = 4, Name = "Coffee Mug", Price = 9.99m, Category = "Kitchen", Stock = 20 }
};

// 用户过滤条件
decimal maxPrice = 500.00m;
string desiredCategory = "Electronics";
int minStock = 5;

var filteredProducts = products.Where(p => 
    p.Price <= maxPrice && 
    p.Category == desiredCategory && 
    p.Stock >= minStock);

Console.WriteLine("符合条件的商品:");
foreach (var product in filteredProducts)
{
    Console.WriteLine($"{product.Name} - ${product.Price}");
}

输出:

符合条件的商品:
Smartphone - $699.99

案例2:日志文件分析[编辑 | 编辑源代码]

从日志条目中筛选出特定级别的错误:

public class LogEntry
{
    public DateTime Timestamp { get; set; }
    public string Level { get; set; }
    public string Message { get; set; }
}

List<LogEntry> logs = new List<LogEntry>
{
    new LogEntry { Timestamp = DateTime.Now.AddHours(-1), Level = "INFO", Message = "System started" },
    new LogEntry { Timestamp = DateTime.Now.AddMinutes(-30), Level = "WARNING", Message = "Disk space low" },
    new LogEntry { Timestamp = DateTime.Now.AddMinutes(-5), Level = "ERROR", Message = "Database connection failed" }
};

// 只显示ERROR级别的日志
var errorLogs = logs.Where(log => log.Level == "ERROR");

foreach (var log in errorLogs)
{
    Console.WriteLine($"[{log.Level}] {log.Timestamp}: {log.Message}");
}

输出:

[ERROR] 5/15/2023 2:55:00 PM: Database connection failed

高级过滤技巧[编辑 | 编辑源代码]

动态过滤[编辑 | 编辑源代码]

可以使用变量动态构建过滤条件:

Func<Product, bool> filter = p => true; // 初始化为不过滤

// 根据用户输入动态添加条件
if (userWantsElectronics)
    filter = p => p.Category == "Electronics";

if (userHasMaxPrice)
    filter = p => filter(p) && p.Price <= userMaxPrice;

var results = products.Where(filter);

使用索引过滤[编辑 | 编辑源代码]

`Where`方法有一个重载版本可以接受元素的索引:

// 只选择偶数索引位置的元素
var everyOther = numbers.Where((num, index) => index % 2 == 0);

性能考虑[编辑 | 编辑源代码]

  • 延迟执行:LINQ查询通常是延迟执行的,只有在实际枚举结果时才会应用过滤条件。
  • 多次枚举:如果多次枚举同一个查询结果,过滤条件会重复执行。可以使用`ToList()`或`ToArray()`缓存结果。
  • IQueryable vs IEnumerable:对于数据库查询,`IQueryable`会将过滤条件转换为SQL,在数据库端执行,效率更高。

常见问题[编辑 | 编辑源代码]

空集合处理[编辑 | 编辑源代码]

对null集合调用LINQ方法会抛出异常。可以使用空集合模式:

var safeCollection = possiblyNullCollection ?? Enumerable.Empty<T>();
var filtered = safeCollection.Where(...);

区分null和空字符串[编辑 | 编辑源代码]

// 只选择非null且非空的字符串
var validStrings = stringCollection.Where(s => !string.IsNullOrEmpty(s));

总结[编辑 | 编辑源代码]

LINQ过滤是处理数据集合的强大工具,通过`Where`方法可以简洁地表达复杂的过滤逻辑。关键点包括:

  • 两种语法形式(查询语法和方法语法)
  • 支持简单和复杂的过滤条件
  • 延迟执行特性
  • 适用于各种数据源
  • 提供动态构建查询的能力

掌握LINQ过滤将显著提高你的C#编程效率和代码可读性。