VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • LINQ to Objects——C#编写员工数据筛选与统计

第一部分:C#基础入门
5.LINQ to Objects——员工数据筛选与统计
实例介绍
LINQ to Objects 是.NET中针对内存集合(如List、Array)的查询技术,它允许vb.net教程C#教程python教程SQL教程access 2010教程你用类似SQL的语法或方法链来操作集合数据,替代传统的循环+判断逻辑,让代码更简洁、易读、易维护。
在实际开发中,员工数据处理是典型场景:比如从员工列表中筛选特定部门的高工资员工、按部门统计人数、计算平均工资等。本实例将通过LINQ to Objects实现这些功能,带你掌握LINQ的核心操作,理解其“声明式编程”的本质(只描述“要什么”,不关心“怎么实现”)。
需求分析
1.定义员工模型:Employee类包含以下属性:
1.Id(员工ID,int);
2.Name(姓名,string);
3.Department(部门,string,如“技术部”“人事部”);
4.Salary(月薪,decimal);
5.HireDate(入职时间,DateTime);
2.核心功能:
1.筛选:找出“技术部”且工资>8000的员工;
2.排序:按工资降序排列员工;
3.统计:计算所有员工的平均工资、最高工资;
4.分组:按部门分组,统计每个部门的人数和平均工资;
5.查找:找出入职时间最早的员工;
3.代码要求:同时展示LINQ查询语法(类似SQL)和方法语法(方法链),对比两种风格的差异;
4.异常处理:处理空集合、无效数据(如工资为负数)的情况。
代码实现
csharp

	using System;
	using System.Collections.Generic;
	using System.Linq;
	
	namespace LinqToObjectsDemo
	{
	// ==================== 1. 员工模型类 ====================
	public class Employee
	{
	public int Id { get; set; }
	public string Name { get; set; } = string.Empty;
	public string Department { get; set; } = string.Empty;
	public decimal Salary { get; set; }
	public DateTime HireDate { get; set; }
	}
	
	// ==================== 2. 测试程序 ====================
	class Program
	{
	static void Main(string[] args)
	{
	// 步骤1:创建测试员工数据
	List<Employee> employees = new List<Employee>
	{
	new() { Id = 1, Name = "张三", Department = "技术部", Salary = 9500, HireDate = new DateTime(2020, 5, 1) },
	new() { Id = 2, Name = "李四", Department = "技术部", Salary = 8200, HireDate = new DateTime(2021, 3, 15) },
	new() { Id = 3, Name = "王五", Department = "人事部", Salary = 6800, HireDate = new DateTime(2019, 10, 8) },
	new() { Id = 4, Name = "赵六", Department = "技术部", Salary = 7500, HireDate = new DateTime(2022, 1, 20) },
	new() { Id = 5, Name = "孙七", Department = "销售部", Salary = 10200, HireDate = new DateTime(2018, 7, 30) },
	new() { Id = 6, Name = "周八", Department = "销售部", Salary = 8800, HireDate = new DateTime(2021, 9, 1) }
	};
	
	// 步骤2:LINQ操作演示
	Console.WriteLine("=== 1. 筛选技术部工资>8000的员工(查询语法) ===");
	var highSalaryTechEmployees = from emp in employees
	where emp.Department == "技术部" && emp.Salary > 8000
	select emp;
	PrintEmployees(highSalaryTechEmployees);
	
	Console.WriteLine("
=== 2. 按工资降序排序(方法语法) ===");
	var sortedBySalary = employees.OrderByDescending(emp => emp.Salary);
	PrintEmployees(sortedBySalary);
	
	Console.WriteLine("
=== 3. 统计所有员工平均工资 ===");
	decimal avgSalary = employees.Average(emp => emp.Salary);
	Console.WriteLine($"平均工资:{avgSalary:C}"); // C表示货币格式
	
	Console.WriteLine("
=== 4. 按部门分组统计(人数+平均工资) ===");
	var deptGroup = from emp in employees
	group emp by emp.Department into deptGroup
	select new
	{
	Department = deptGroup.Key,
	Count = deptGroup.Count(),
	AvgSalary = deptGroup.Average(emp => emp.Salary)
	};
	foreach (var group in deptGroup)
	{
	Console.WriteLine($"部门:{group.Department} | 人数:{group.Count} | 平均工资:{group.AvgSalary:C}");
	}
	
	Console.WriteLine("
=== 5. 查找入职时间最早的员工 ===");
	Employee earliestHire = employees.OrderBy(emp => emp.HireDate).FirstOrDefault()!;
	Console.WriteLine($"最早入职:{earliestHire.Name} | 入职时间:{earliestHire.HireDate:yyyy-MM-dd}");
	}
	
	// 辅助方法:打印员工列表
	static void PrintEmployees(IEnumerable<Employee> employees)
	{
	foreach (var emp in employees)
	{
	Console.WriteLine($"ID:{emp.Id} | 姓名:{emp.Name} | 部门:{emp.Department} | 工资:{emp.Salary:C}");
	}
	}
	}
	}

逐行讲解

  1. 员工模型类(Employee)
    csharp
	public class Employee
	{
	public int Id { get; set; }
	public string Name { get; set; } = string.Empty;
	public string Department { get; set; } = string.Empty;
	public decimal Salary { get; set; }
	public DateTime HireDate { get; set; }
	}

包含员工核心属性,string类型初始化= string.Empty避免空引用;
decimal用于工资(避免浮点精度丢失),DateTime用于入职时间。
2. 测试数据创建
csharp

	List<Employee> employees = new List<Employee>
	{
	new() { Id =1, Name="张三", Department="技术部", Salary=9500, HireDate=new DateTime(2020,5,1) },
	// ...其他员工
	};

用对象初始化器快速创建员工列表,替代传统的new Employee(); emp.Id=1;写法。
3. LINQ操作详解
(1)筛选员工(查询语法)
csharp

	var highSalaryTechEmployees = from emp in employees
	where emp.Department == "技术部" && emp.Salary >8000
	select emp;

from emp in employees:指定查询的数据源(员工列表),emp是集合中每个元素的别名;
where:筛选条件(部门为技术部且工资>8000);
select emp:指定返回结果(完整的员工对象);
延迟执行:此时LINQ并未真正执行查询,直到调用PrintEmployees(枚举集合)时才会计算结果。
(2)按工资降序排序(方法语法)
csharp
var sortedBySalary = employees.OrderByDescending(emp => emp.Salary);
OrderByDescending:LINQ扩展方法,接受一个Lambda表达式(emp => emp.Salary)作为排序键;
方法链:可以继续追加操作,比如employees.OrderByDescending(...).ThenBy(emp=>emp.Name)(工资相同则按姓名排序)。
(3)统计平均工资
csharp
decimal avgSalary = employees.Average(emp => emp.Salary);
Average:聚合函数,计算指定属性的平均值;
立即执行:调用Average时会立即遍历集合,返回结果(区别于延迟执行的查询)。
(4)按部门分组统计
csharp

	var deptGroup = from emp in employees
	group emp by emp.Department into deptGroup
	select new
	{
	Department = deptGroup.Key,
	Count = deptGroup.Count(),
	AvgSalary = deptGroup.Average(emp => emp.Salary)
	};

group emp by emp.Department:按部门分组,deptGroup是分组后的结果(类型为IGrouping<string, Employee>);
into deptGroup:将分组结果重命名为deptGroup,以便后续操作;
匿名类型:select new { ... }创建一个临时对象,包含部门名称、人数、平均工资(无需定义实体类)。
(5)查找最早入职员工
csharp
Employee earliestHire = employees.OrderBy(emp => emp.HireDate).FirstOrDefault()!;
OrderBy:按入职时间升序排序;
FirstOrDefault:返回排序后的第一个元素(入职最早),若集合为空则返回null(!表示非空断言,确保结果不为空)。
基础知识拓展

  1. LINQ核心概念
    概念 说明
    延迟执行 LINQ查询在枚举集合(如foreach、ToList)时才执行,节省内存(无需提前存储所有结果);
    立即执行 调用聚合函数(Average、Count、Sum)或ToList()/ToArray()时,立即执行查询并返回结果;
    查询语法 vs 方法语法 查询语法更接近SQL,易读;方法语法更灵活,支持链式调用;两者可以混合使用(比如from...where...select+OrderBy);
    Lambda表达式 LINQ方法语法的核心,用于传递筛选条件、排序键等(格式:(参数) => 表达式);
  2. 常见LINQ操作符分类
分类 示例方法/关键字 作用
筛选 Where、OfType 从集合中筛选符合条件的元素;
排序 OrderBy、OrderByDescending、ThenBy 对集合进行排序;
投影 Select、SelectMany 转换集合元素(比如只返回员工姓名:employees.Select(emp=>emp.Name));
聚合 Average、Count、Sum、Max 计算集合的统计值;
分组 group by、GroupBy 按指定键分组;
连接 Join、GroupJoin 类似SQL的JOIN操作(比如员工表与部门表连接);
  1. LINQ vs 传统循环
    以“筛选技术部高工资员工”为例,对比两种写法:
    传统循环:
    csharp
	List<Employee> result = new List<Employee>();
	foreach (var emp in employees)
	{
	if (emp.Department == "技术部" && emp.Salary >8000)
	{
	result.Add(emp);
	}
	}

LINQ:
csharp

var result = employees.Where(emp => emp.Department == "技术部" && emp.Salary>8000);

优势:LINQ代码更简洁,无需手动管理临时集合,且可读性更高(一眼就能看出要筛选什么)。
扩展思考
1.处理空集合:如果员工列表为空,Average会抛出InvalidOperationException,如何避免?
用employees.DefaultIfEmpty().Average(...)(空集合时返回0);
或先判断employees.Any()(是否有元素)再执行聚合操作。
2.自定义排序:如何按“姓名长度”排序?
oemployees.OrderBy(emp => emp.Name.Length);
3.复杂筛选:如何筛选“入职时间在2020年之后且工资>9000”的员工?
查询语法:where emp.HireDate.Year >=2020 && emp.Salary>9000;
方法语法:employees.Where(emp => emp.HireDate.Year>=2020 && emp.Salary>9000);
4.性能优化:对于大数据量集合,LINQ的延迟执行会多次枚举吗?
会!如果多次使用同一个LINQ查询(比如highSalaryTechEmployees),会多次遍历集合;
优化方案:用ToList()将结果缓存到内存(var result = highSalaryTechEmployees.ToList())。
总结
LINQ to Objects是.NET开发者的必备技能,它彻底改变了集合数据的处理方式——从“命令式编程”(告诉计算机“怎么做”)转向“声明式编程”(告诉计算机“要什么”)。通过本实例的员工数据处理,你应该掌握了LINQ的核心操作:筛选、排序、聚合、分组,以及两种语法的使用场景。
在实际开发中,LINQ可以大幅减少代码量,提高可读性和可维护性。建议多尝试用LINQ替代传统循环,逐渐养成“声明式编程”的思维习惯。

本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49417.html


相关教程