-
控制台高级交互——用C#开发菜单驱动式应用程序
第一部分:C#基础入门
实例10:控制台高级交互——菜单驱动式应用程序
实例介绍
菜单驱动式应用是控制台程序的经典形态,广泛用于管理系统、工具类程序等场景。用户通过选择数字/字母来触发功能,核心是交互流程的流畅性和输入的鲁棒性(防止非法输入崩溃)。本实例通过实现一个学生信息管理系统的控制台菜单,掌握多级菜单设计、输入验证、循环控制、状态保存等核心技巧,让控制台程序既实用又友好。
需求分析
1.多级菜单结构:主菜单包含「学生信息管理」「成绩管理」「退出」,子菜单(如学生管理)包含「添加学生」「查看学生」「返回主菜单」;
2.输入验证:仅允许合法数字选择(如主菜单只能输入1-3),非法输入时提vb.net教程C#教程python教程SQL教程access 2010教程
示并重新输入;
3.菜单循环:用户操作后不直接退出,返回当前菜单继续操作;
4.数据暂存:用列表保存添加的学生信息,支持查看;
5.友好提示:操作成功/失败时给出清晰反馈,错误输入时引导用户;
6.安全退出:提供明确的退出选项,避免程序强制终止。
代码实现
csharp
using System;
using System.Collections.Generic;
namespace MenuDrivenAppDemo
{
// 学生信息类:存储基础数据
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return $"ID:{Id} | 姓名:{Name} | 年龄:{Age}";
}
}
// 静态数据存储类:全局共享学生信息
public static class DataStore
{
public static List<Student> Students = new List<Student>();
private static int _nextStudentId = 1; // 自动生成ID
// 获取下一个学生ID(自增)
public static int GetNextStudentId() => _nextStudentId++;
}
// 菜单驱动主程序
class Program
{
static void Main(string[] args)
{
ShowMainMenu(); // 启动主菜单
}
#region 主菜单逻辑
private static void ShowMainMenu()
{
while (true) // 菜单循环:直到用户选择退出
{
Console.Clear(); // 清空控制台,提升体验
Console.WriteLine("=== 学生信息管理系统 ===");
Console.WriteLine("1. 学生信息管理");
Console.WriteLine("2. 成绩管理(待实现)");
Console.WriteLine("3. 退出程序");
Console.Write("请输入选择(1-3):");
// 获取合法输入(仅允许1-3)
int choice = GetValidIntegerInput(1, 3);
switch (choice)
{
case 1:
ShowStudentSubMenu(); // 进入学生管理子菜单
break;
case 2:
ShowNotImplementedMessage(); // 提示功能未实现
break;
case 3:
Console.WriteLine("感谢使用,再见!");
Console.ReadKey();
return; // 退出程序
}
}
}
#endregion
#region 学生管理子菜单逻辑
private static void ShowStudentSubMenu()
{
while (true)
{
Console.Clear();
Console.WriteLine("=== 学生信息管理子菜单 ===");
Console.WriteLine("1. 添加学生");
Console.WriteLine("2. 查看所有学生");
Console.WriteLine("3. 返回主菜单");
Console.Write("请输入选择(1-3):");
int choice = GetValidIntegerInput(1, 3);
switch (choice)
{
case 1:
AddStudent();
break;
case 2:
ViewAllStudents();
break;
case 3:
return; // 返回主菜单
}
}
}
#endregion
#region 功能实现
private static void AddStudent()
{
Console.Clear();
Console.WriteLine("=== 添加学生 ===");
// 获取学生姓名(非空验证)
string name;
while (true)
{
Console.Write("请输入学生姓名:");
name = Console.ReadLine()?.Trim() ?? "";
if (!string.IsNullOrEmpty(name)) break;
Console.WriteLine("姓名不能为空,请重新输入!");
}
// 获取学生年龄(1-100)
Console.Write("请输入学生年龄:");
int age = GetValidIntegerInput(1, 100);
// 生成ID并添加到列表
int studentId = DataStore.GetNextStudentId();
DataStore.Students.Add(new Student
{
Id = studentId,
Name = name,
Age = age
});
Console.WriteLine($"添加成功!学生ID:{studentId}");
WaitForKeyPress(); // 等待用户按键返回子菜单
}
private static void ViewAllStudents()
{
Console.Clear();
Console.WriteLine("=== 所有学生信息 ===");
if (DataStore.Students.Count == 0)
{
Console.WriteLine("暂无学生信息!");
}
else
{
foreach (var student in DataStore.Students)
{
Console.WriteLine(student.ToString());
}
}
WaitForKeyPress();
}
#endregion
#region 工具函数(复用逻辑)
/// <summary>
/// 获取合法的整数输入(范围验证)
/// </summary>
/// <param name="min">最小允许值</param>
/// <param name="max">最大允许值</param>
/// <returns>合法的整数</returns>
private static int GetValidIntegerInput(int min, int max)
{
int input;
while (true)
{
string inputStr = Console.ReadLine()?.Trim() ?? "";
if (int.TryParse(inputStr, out input) && input >= min && input <= max)
{
break; // 输入合法,退出循环
}
Console.Write($"输入无效,请输入{min}-{max}之间的数字:");
}
return input;
}
/// <summary>
/// 等待用户按键(用于操作后暂停)
/// </summary>
private static void WaitForKeyPress()
{
Console.WriteLine("
按任意键继续...");
Console.ReadKey(true); // true:不显示用户按下的键
}
/// <summary>
/// 显示功能未实现提示
/// </summary>
private static void ShowNotImplementedMessage()
{
Console.WriteLine("该功能尚未实现,敬请期待!");
WaitForKeyPress();
}
#endregion
}
}
逐行讲解
-
数据存储类(DataStore)
csharp
public static class DataStore
{
public static List<Student> Students = new List<Student>();
private static int _nextStudentId =1;
public static int GetNextStudentId() => _nextStudentId++;
}
静态类:全局共享数据,无需实例化即可访问;
Students列表:存储所有添加的学生信息;
_nextStudentId:自动生成唯一ID(自增),避免手动输入冲突;
GetNextStudentId:返回当前ID并自增,简化ID管理。
2. 输入验证函数(GetValidIntegerInput)
csharp
private static int GetValidIntegerInput(int min, int max)
{
int input;
while(true)
{
string inputStr = Console.ReadLine()?.Trim() ?? "";
if(int.TryParse(inputStr, out input) && input >= min && input <= max) break;
Console.Write($"输入无效,请输入{min}-{max}之间的数字:");
}
return input;
}
循环验证:直到用户输入合法数字才退出;
int.TryParse:安全解析字符串为整数,避免输入非数字时抛出异常;
范围检查:确保输入在指定范围内(如主菜单只能1-3);
空值处理:用?? ""将null转为空字符串,防止Trim()调用时的空引用。
3. 主菜单循环(ShowMainMenu)
csharp
private static void ShowMainMenu()
{
while(true)
{
Console.Clear(); // 清空控制台,保持界面整洁
// ...显示菜单...
int choice = GetValidIntegerInput(1,3);
switch(choice)
{
case1: ShowStudentSubMenu(); break;
case3: return; // 退出程序
}
}
}
while(true):无限循环,直到用户选择退出;
Console.Clear():每次显示菜单前清空屏幕,提升用户体验;
switch-case:根据选择执行对应逻辑,子菜单通过函数调用实现多级结构。
4. 子菜单逻辑(ShowStudentSubMenu)
csharp
private static void ShowStudentSubMenu()
{
while(true)
{
// ...显示子菜单...
int choice = GetValidIntegerInput(1,3);
if(choice ==3) return; // 返回主菜单
// ...处理其他选择...
}
}
返回机制:选择“返回主菜单”时用return退出当前函数,回到主菜单循环;
复用工具函数:输入验证、等待按键等逻辑复用,减少重复代码。
5. 添加学生功能(AddStudent)
csharp
private static void AddStudent()
{
// ...姓名非空验证...
while(true)
{
name = Console.ReadLine()?.Trim() ?? "";
if(!string.IsNullOrEmpty(name)) break;
}
// ...年龄验证...
DataStore.Students.Add(new Student{Id=studentId, Name=name, Age=age});
}
姓名非空验证:用循环强制用户输入非空姓名;
年龄范围验证:复用GetValidIntegerInput确保年龄在1-100之间;
自动ID:调用DataStore.GetNextStudentId生成唯一ID,无需用户干预。
基础知识拓展
- 控制台交互核心技巧
| 方法/属性 | 作用 | 示例 |
|---|---|---|
| Console.Clear() | 清空控制台屏幕 | Console.Clear() |
| Console.ReadKey(bool intercept) | 获取用户按键,intercept=true时不显示按键 | Console.ReadKey(true) |
| Console.ForegroundColor | 设置输出文字颜色 | Console.ForegroundColor = ConsoleColor.Green |
| int.TryParse(string s, out int result) | 安全解析字符串为整数,返回是否成功 | int.TryParse(inputStr, out input) |
-
循环控制的选择
while(true):适合无限循环(如菜单),需手动用break/return退出;
do-while:适合至少执行一次的场景(如输入验证);
for:适合固定次数的循环(如遍历列表)。 -
多级菜单的实现方式
函数嵌套:如主菜单调用子菜单函数,子菜单用return返回主菜单;
状态机:用枚举表示当前菜单状态(如MenuState.Main/MenuState.StudentSub),通过switch-case处理;
配置化菜单:用字典存储菜单选项(如Dictionary<int, Action>),动态添加菜单功能。 -
代码复用的重要性
工具函数:将输入验证、等待按键等通用逻辑封装为函数,减少重复代码;
静态类:如DataStore,集中管理共享数据,避免全局变量的混乱;
面向对象:用Student类封装数据,提升代码可读性和可维护性。
扩展思考
1.菜单美化:添加颜色(如标题用绿色,错误提示用红色);
2.数据持久化:将学生信息保存到文件(如JSON/CSV),下次启动时加载;
3.快捷键支持:如按ESC键直接退出程序;
4.错误处理:用try-catch捕获异常(如文件读写错误);
5.菜单配置化:用List存储菜单选项,动态生成菜单;
6.分页功能:当学生数量过多时,实现分页查看。
总结
菜单驱动式应用的核心是用户体验和逻辑清晰:
输入验证是鲁棒性的关键,避免非法输入导致程序崩溃;
循环控制是菜单流程的基础,确保用户操作后不退出;
代码复用提升开发效率,减少维护成本;
多级菜单通过函数嵌套实现,结构清晰易扩展。
掌握这些技巧,你可以轻松构建各种控制台管理系统,为后续学习桌面应用或Web开发打下坚实基础。
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49401.html










