项目涉及知识点
| 知识点 | 说明 |
|---|---|
| 泛型类 | Dal实现数据存储与增删改查 |
| 泛型接口 | IDal定义数据访问契约 |
| 泛型约束 | where T : People限制类型必须继承自People |
| 抽象类 | People定义公共属性与行为模板 |
| 继承 | Boy、Girl继承自People |
| 枚举 | Gender定义性别常量 |
| 构造函数 | 基类受保护构造 + 子类构造调用base() |
| 方法重写 | ToString()重写实现自定义输出 |
| Lambda 表达式 | p => p.Name == item.Name简化集合操作 |
| LINQ 方法 | Any()、FirstOrDefault()、ToArray() |
| 多态 | 接口引用指向实现类对象 |
| 访问修饰符 | protected set、protected构造 |
| 异常处理 | throw主动抛出业务异常 |
| 类型判断与转换 | typeof(T)+(T)(object)强制转换 |
1. 枚举(Enum)
csharp
public enum Gender { Male = 1, Female = 2 }2. 抽象基类People(抽象类 + 受保护构造 + 虚方法重写)
csharp
public abstract class People { public string Name { get; set; } public int Age { get; set; } public Gender Sex { get; protected set; } // 派生类可修改 public double Score { get; set; } // 受保护构造:只让子类调用 protected People(string name, int age, Gender sex, double score) { Name = name; Age = age; Sex = sex; Score = score; } // 重写 ToString,方便输出 public override string ToString() { return $"{Name} {Age}岁 {(Sex == Gender.Male ? "男" : "女")} {Score}分"; } }3. 子类Boy/Girl(继承 +base()调用父类构造)
csharp
public class Boy : People { public string Play_Game { get; set; } = "LOL"; public Boy(string name, int age, double score) : base(name, age, Gender.Male, score) // 固定性别为男 { // 父类构造已完成赋值 } } public class Girl : People { public string Go_Shopping { get; set; } = "购物"; public Girl(string name, int age, double score) : base(name, age, Gender.Female, score) // 固定性别为女 { } }4. 泛型接口IDal(接口 + 泛型约束)
csharp
// 泛型接口,约束 T 必须是 People 或其派生类 public interface IDal<T> where T : People { void Add(T item); bool Remove(string name); // 按名字删除 void Update(string name, T newValue); T FindOne(string name); IEnumerable<T> GetAll(); }5. 泛型实现类Dal(泛型类 + Lambda + LINQ)
csharp
public class Dal<T> : IDal<T> where T : People { private readonly List<T> _list = new List<T>(); // 添加(使用 Any 检查重复) public void Add(T item) { bool isFlag = _list.Any(p => p.Name == item.Name); if (isFlag) throw new InvalidOperationException($"该学生已存在:{item.Name}"); _list.Add(item); } // 查询全部 public IEnumerable<T> GetAll() => _list.ToArray(); // 按名字查找(FirstOrDefault) public T FindOne(string name) => _list.FirstOrDefault(p => p.Name == name); // 删除 public bool Remove(string name) => _list.Remove(_list.FirstOrDefault(p => p.Name == name)); // 更新 public void Update(string name, T newValue) { var oldObj = _list.FirstOrDefault(p => p.Name == name); if (oldObj != null) { _list[_list.IndexOf(oldObj)] = newValue; } else { throw new KeyNotFoundException($"未找到学生:{name}"); } } }6. 管理器StudentManager(多态 + 类型判断)
csharp
public class StudentManager { // 多态:父接口引用指向子类对象 private readonly IDal<Boy> _boyDal = new Dal<Boy>(); private readonly IDal<Girl> _girlDal = new Dal<Girl>(); public StudentManager() { // 默认初始化两条数据 _boyDal.Add(new Boy("张三", 18, 88.5)); _girlDal.Add(new Girl("小雨", 28, 100)); } // 根据类型返回对应的 Dal public IDal<T> GetDal<T>() where T : People { if (typeof(T) == typeof(Boy)) return (IDal<T>)_boyDal; if (typeof(T) == typeof(Girl)) return (IDal<T>)_girlDal; throw new NotSupportedException("不支持的类型"); } }7. Program 主程序(类型转换 + 泛型方法调用)
csharp
internal class Program { private static readonly StudentManager _mgr = new StudentManager(); static void Main(string[] args) { // 选择男生或女生 switch (Console.ReadLine()) { case "1": RunSubMenu<Boy>(); break; case "2": RunSubMenu<Girl>(); break; case "0": return; } } private static void RunSubMenu<T>() where T : People { var dal = _mgr.GetDal<T>(); // 获取对应类型的 Dal // 循环显示菜单,调用 Add/Remove/Update/Query } // 添加(类型判断 + 强制转换) private static void Add<T>(IDal<T> dal) where T : People { // 根据 T 的类型决定创建 Boy 还是 Girl T item = typeof(T) == typeof(Boy) ? (T)(object)new Boy(name, age, score) : (T)(object)new Girl(name, age, score); dal.Add(item); } }8. 关键技术对比总结
泛型接口 vs 泛型类
| 特性 | 泛型接口IDal | 泛型类Dal |
|---|---|---|
| 作用 | 定义契约,统一规范 | 提供具体实现 |
| 实例化 | 不能实例化 | 可实例化new Dal() |
| 多态 | 可作为引用类型 | 实现接口,可向上转型 |
Lambda 表达式对照
| 传统写法 | Lambda 简写 |
|---|---|
_list.Any(delegate(T p) { return p.Name == name; }); | _list.Any(p => p.Name == name) |
_list.FirstOrDefault(delegate(T p) { return p.Name == name; }); | _list.FirstOrDefault(p => p.Name == name) |
类型判断与转换
| 场景 | 代码 |
|---|---|
| 判断泛型类型 | typeof(T) == typeof(Boy) |
| 强制转换(先转 object) | (T)(object)new Boy(name, age, score) |
| 获取类型名称 | typeof(T).Name |
9. 类图关系(简化)
text
┌─────────────────┐ │ <<interface>> │ │ IDal<T> │ │ +Add() │ │ +Remove() │ │ +Update() │ │ +FindOne() │ │ +GetAll() │ └────────┬────────┘ │ 实现 ▼ ┌─────────────────┐ ┌─────────────────┐ │ Dal<T> │────────│ People │◄────── 抽象类 │ -_list │ 约束 │ -Name │ │ +Add() │ T:People│ -Age │ │ +Remove() │ │ -Sex │ │ +Update() │ │ -Score │ │ +FindOne() │ │ +ToString() │ │ +GetAll() │ └────────┬────────┘ └─────────────────┘ │ 继承 ├───────────┐ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ Boy │ │ Girl │ │ +Play_Game │ │+Go_Shopping │ └─────────────┘ └─────────────┘10. 一句话记忆
- 抽象类
People→ 定义公共属性,不实例化 protected构造→ 只让子类调用- 泛型接口
IDal→ 统一数据访问契约 - 泛型类
Dal→ 实现具体的增删改查 where T : People→ 限制类型必须是 People 的子类- Lambda 表达式
p => p.Name == name→ 简化集合查找 typeof(T)→ 运行时判断泛型的具体类型(T)(object)→ 先装箱再拆箱,绕过类型转换限制
完整代码------------------------------------------------------------------
1. Model 层(数据模型)
1.1 Gender 枚举 ——Model/Gender.cs
csharp
namespace _1.学生管理系统.Model { public enum Gender { Male = 1, Female = 2 } }1.2 People 抽象类 ——Model/People.cs
csharp
using System; namespace _1.学生管理系统.Model { // 抽象类:定义公共属性,不实例化 public abstract class People { public string Name { get; set; } public int Age { get; set; } public Gender Sex { get; protected set; } // 派生类可修改 public double Score { get; set; } // 受保护构造:只让子类调用 protected People(string name, int age, Gender sex, double score) { Name = name; Age = age; Sex = sex; Score = score; } // 重写 ToString,方便输出 public override string ToString() { return $"{Name} {Age}岁 {(Sex == Gender.Male ? "男" : "女")} {Score}分"; } } }1.3 Boy 类 ——Model/Boy.cs
csharp
namespace _1.学生管理系统.Model { public class Boy : People { public string Play_Game { get; set; } = "LOL"; public Boy(string name, int age, double score) : base(name, age, Gender.Male, score) // 固定性别为男 { } } }1.4 Girl 类 ——Model/Girl.cs
csharp
namespace _1.学生管理系统.Model { public class Girl : People { public string Go_Shopping { get; set; } = "购物"; public Girl(string name, int age, double score) : base(name, age, Gender.Female, score) // 固定性别为女 { } } }2. DAL 层(数据访问层)
2.1 IDal 泛型接口 ——DAL/IDal.cs
csharp
using _1.学生管理系统.Model; namespace _1.学生管理系统.DAL { // 泛型接口,约束 T 必须是 People 或其派生类 public interface IDal<T> where T : People { void Add(T item); bool Remove(string name); void Update(string name, T newValue); T FindOne(string name); IEnumerable<T> GetAll(); } }2.2 Dal 泛型实现类 ——DAL/Dal.cs
csharp
using _1.学生管理系统.Model; namespace _1.学生管理系统.DAL { public class Dal<T> : IDal<T> where T : People { private readonly List<T> _list = new List<T>(); // ===== 添加模块 ===== public void Add(T item) { // 检查姓名是否重复 bool isFlag = _list.Any(p => p.Name == item.Name); if (isFlag) throw new InvalidOperationException($"该学生已存在:{item.Name}"); _list.Add(item); } // ===== 查询全部模块 ===== public IEnumerable<T> GetAll() => _list.ToArray(); // ===== 按名字查找模块 ===== public T FindOne(string name) => _list.FirstOrDefault(p => p.Name == name); // ===== 删除模块 ===== public bool Remove(string name) { // 先查找,再删除 return _list.Remove(_list.FirstOrDefault(p => p.Name == name)); } // ===== 更新模块 ===== public void Update(string name, T newValue) { var oldObj = _list.FirstOrDefault(p => p.Name == name); if (oldObj != null) { _list[_list.IndexOf(oldObj)] = newValue; } else { throw new KeyNotFoundException($"未找到学生:{name}"); } } } }3. Manager 层(业务管理层)
3.1 StudentManager 管理器 ——Manager/StudentManager.cs
csharp
using _1.学生管理系统.DAL; using _1.学生管理系统.Model; namespace _1.学生管理系统.Manager { public class StudentManager { // 多态:父接口引用指向子类对象 private readonly IDal<Boy> _boyDal = new Dal<Boy>(); private readonly IDal<Girl> _girlDal = new Dal<Girl>(); // ===== 构造函数:初始化默认数据 ===== public StudentManager() { _boyDal.Add(new Boy("张三", 18, 88.5)); _girlDal.Add(new Girl("小雨", 28, 100)); } // ===== 获取 Dal 模块 ===== public IDal<T> GetDal<T>() where T : People { if (typeof(T) == typeof(Boy)) return (IDal<T>)_boyDal; if (typeof(T) == typeof(Girl)) return (IDal<T>)_girlDal; throw new NotSupportedException("不支持的类型,必须是People的派生"); } } }4. Program 主程序(UI 层)
4.1 Program 类 ——Program.cs
csharp
using _1.学生管理系统.DAL; using _1.学生管理系统.Manager; using _1.学生管理系统.Model; namespace _1.学生管理系统 { internal class Program { private static readonly StudentManager _mgr = new StudentManager(); // ===== 主入口模块 ===== static void Main(string[] args) { Console.Clear(); Console.WriteLine("=======学生管理系统======="); Console.WriteLine("1.请选择男生"); Console.WriteLine("2.请选择女生"); Console.WriteLine("0.退出"); Console.Write("请选择:"); switch (Console.ReadLine()) { case "1": RunSubMenu<Boy>(); break; case "2": RunSubMenu<Girl>(); break; case "0": return; default: break; } } // ===== 子菜单模块(通用,T 可以是 Boy 或 Girl) ===== private static void RunSubMenu<T>() where T : People { var dal = _mgr.GetDal<T>(); while (true) { Console.Clear(); Console.WriteLine($"======={(typeof(T) == typeof(Boy) ? "男生" : "女生")}列表======="); foreach (var s in dal.GetAll()) Console.WriteLine(s); Console.WriteLine("-----------------------------------"); Console.WriteLine("1.新增 2.删除 3.修改 4.查询 5.返回上级"); Console.Write("请选择:"); switch (Console.ReadLine()) { case "1": Add(dal); break; case "2": Remove(dal); break; case "3": Update(dal); break; case "4": Query(dal); break; case "5": return; default: break; } } } // ===== 添加模块 ===== private static void Add<T>(IDal<T> dal) where T : People { Console.Write("姓名:"); var name = Console.ReadLine(); Console.Write("年龄:"); var age = int.Parse(Console.ReadLine()); Console.Write("分数:"); var score = double.Parse(Console.ReadLine()); // 类型判断 + 强制转换 T item = typeof(T) == typeof(Boy) ? (T)(object)new Boy(name, age, score) : (T)(object)new Girl(name, age, score); dal.Add(item); Console.WriteLine("添加成功"); } // ===== 删除模块 ===== private static void Remove<T>(IDal<T> dal) where T : People { Console.Write("请输入要删除的名字:"); var ok = dal.Remove(Console.ReadLine()); Console.WriteLine(ok ? "删除成功" : "未找到"); Console.ReadKey(); } // ===== 修改模块 ===== private static void Update<T>(IDal<T> dal) where T : People { Console.Write("请输入要修改的学生姓名:"); var oldName = Console.ReadLine(); Console.Write("姓名:"); var name = Console.ReadLine(); Console.Write("年龄:"); var age = int.Parse(Console.ReadLine()); Console.Write("分数:"); var score = double.Parse(Console.ReadLine()); T newItem = typeof(T) == typeof(Boy) ? (T)(object)new Boy(name, age, score) : (T)(object)new Girl(name, age, score); dal.Update(oldName, newItem); Console.WriteLine("修改成功"); } // ===== 查询模块 ===== private static void Query<T>(IDal<T> dal) where T : People { Console.Write("请输入要查询的学生姓名:"); var stu = dal.FindOne(Console.ReadLine()); Console.WriteLine(stu == null ? "未找到" : stu.ToString()); Console.ReadKey(); } } }5. 项目结构图
text
_1.学生管理系统/ │ ├── Model/ # 数据模型层 │ ├── Gender.cs # 枚举:性别 │ ├── People.cs # 抽象类:公共属性 │ ├── Boy.cs # 男孩类(继承 People) │ └── Girl.cs # 女孩类(继承 People) │ ├── DAL/ # 数据访问层 │ ├── IDal.cs # 泛型接口:定义 CRUD 契约 │ └── Dal.cs # 泛型类:实现 CRUD │ ├── Manager/ # 业务管理层 │ └── StudentManager.cs # 管理器:管理 Boy/Girl 的 Dal │ └── Program.cs # UI 层:主程序入口6. 核心机制速查表
| 模块 | 类/接口 | 核心功能 | 关键代码 |
|---|---|---|---|
| Model | People | 定义公共属性 | protected People(...) |
| Model | Boy | 男生特有属性 | : base(..., Gender.Male, ...) |
| Model | Girl | 女生特有属性 | : base(..., Gender.Female, ...) |
| DAL | IDal | 数据访问契约 | void Add(T item) |
| DAL | Dal | 数据存储实现 | _list.Any(p => p.Name == name) |
| Manager | StudentManager | 获取对应 Dal | return (IDal)_boyDal |
| Program | RunSubMenu | 通用子菜单 | where T : People |
| Program | Add | 添加学生 | (T)(object)new Boy(...) |