介绍我写的控制台应用工具类,实现以下功能:
(1) 输入密码。用户输入密码时,控制台显示****而不是密码明文;
(2) 指令的解析与分派。控制台中,经常需要向程序输入纯字符串格式的指令,解析指令,解析参数的个数,调用相应的方法。
(3) 指令的帮助系统。显示全部指令及其介绍。
(4) 指令的自动补全。
一、简介
控制台程序小巧、便捷,开发起来简单。一般,我写项目时习惯在原定客户端之外,写一个控制台的客户端。这样有几个好处:
(1) 开发量较Web或GUI少得多。
(2) 运行起来简单,占有资源很少。
(3) 便于跟踪程序的运行。比如,用 log4net 记录日志的话,将appender-ref设置成ConsoleAppender,可以清楚看清系统运行轨迹,在使用nhibernate/activerecord开发时尤其方便。
(4) 当为同一个系统开发两种不同的UI时,会自觉的做好分层,这样可以使系统的层次结构更清晰,便于维护。
然而,虽然控制台程序的开发量少,也还是有一些常用功能实现起来较繁琐。比如,以下几个问题:
(1) 输入密码。用户输入密码时,控制台显示****而不是密码明文;
(2) 指令的解析与分派。控制台中,经常需要向程序输入纯字符串格式的指令,解析指令,解析参数的个数,调用相应的方法。
(3) 指令的帮助系统。显示全部指令及其介绍。
(4) 指令的自动补全。
这几个问题在写控制台程序上经常会碰到,为此我写了两个类 ConsoleUtil 和 CmdDispatcher,实现了上述功能,以供复用。于此下载代码。
代码是C#3.0 写的,若要用在其它C#版本,需要做一定的改动。
二、使用方式:
(1) 输入密码
调用静态方法String ConsoleUtil.ReadPassword(String msg, String errMsgOnNull) 获取输入的密码。
(2) 指令的解析、分派、自动补全与帮助系统
(a)创建一个 CmdDispatcher 对象。
(b)使用CmdDispatcher对象的AddCmdFunc方法,加入指令委托。这里定义了五种委托:
delegate void Func0();
delegate void Func1(String s1);
delegate void Func2(String s1, String s2);
delegate void Func3(String s1, String s2, String s3);
delegate void Func4(String s1, String s2, String s3, String s4);

AddCmdFunc方法有两种使用方式。
AddCmdFunc(String cmd, Func0|Func1|Func2|Func3|Func4 func)
和
AddCmdFunc(String cmd, String argsString, String introduce, Func0|Func1|Func2|Func3|Func4 func)
后一种方式中 argsString 是该指令的参数字符串,introduce 是对这个指令的介绍。这两个变量的唯一意义是显示在该指令的help信息之中。如果使用前一种方式,该指令的help信息便是光秃秃的。
比如,
CmdDispatcher cd = new CmdDispatcher();
cd.AddCmdFunc("help", "无参数", "查询帮助.",

() =>
{ cd.PrintHelp(); });
cd.AddCmdFunc("cmd1", "无参数", "指令cmd1.",

() =>
{ Console.WriteLine(String.Format("Invoke cmd1.")); });
cd.AddCmdFunc("cmd2", "arg0 arg1", "指令cmd1.",

(arg0, arg1) =>
{ Console.WriteLine(String.Format("Invoke cmd1({0},{1}).", arg0, arg1)); });
cd.AddCmdFunc("cmd3",

(arg0, arg1, arg2) =>
{ Console.WriteLine(String.Format("Invoke cmd1({0},{1},{2}).", arg0, arg1, arg2)); });

显示出来的 help 信息为:
help 无参数
查询帮助.

cmd2 arg0 arg1
指令cmd1.

cmd3 无参数

(3)通过CmdDispatcher对象的String ReadlineWithIntelliSence()方法获取控制台输入的指令.通过CmdDispatcher对象的Handle(String input)方法便可解析指令,分派给相应的委托完成。
举例:
while (true)

{
Console.Write(cd.Prefix); // 在控制台上输出提示符 >>。
String input = cd.ReadlineWithIntelliSence();
cd.Handle(input);
}

(4)不匹配的指令的处理方法
CmdDispatcher
有一个属性,public Func0 DefaultFunc { get; set; } 。
当CmdDispatcher
找不到匹配的委托时,便调用这个delegate
。你可以自行设置 DefaultFunc,否则则用默认的内置 delegate。
三、一个完整的例子
下面是一个完整的例子:
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
6
namespace ConsoleTest
7

{
8
class Program
9
{
10
static Boolean EXIT = false;
11
static void Main(string[] args)
12
{
13
String id = ConsoleUtil.Readline("请输入帐号:","帐号不能为空.");
14
String pwd = ConsoleUtil.ReadPassword("请输入密码:","密码不能为空.");
15
Console.WriteLine("欢迎你,"+ id + "!");
16
CmdDispatcher cd = CreateDispatcher();
17
while (true)
18
{
19
Console.Write(cd.Prefix);
20
String input = cd.ReadlineWithIntelliSence();
21
cd.Handle(input);
22
if (EXIT) return;
23
}
24
}
25
26
static CmdDispatcher CreateDispatcher()
27
{
28
CmdDispatcher cd = new CmdDispatcher();
29
cd.AddCmdFunc("help", "无参数", "查询帮助.",
30
() =>
{ cd.PrintHelp(); });
31
cd.AddCmdFunc("help", "cmd", "查询指定指令的帮助.",
32
(cmd) =>
{ cd.PrintHelp(cmd); });
33
cd.AddCmdFunc("exit","无参数","退出程序.",
34
() =>
{ EXIT = true; });
35
cd.AddCmdFunc("cmd1", "无参数", "指令cmd1.",
36
() =>
{ Console.WriteLine(String.Format("Invoke cmd1.")); });
37
cd.AddCmdFunc("cmd1", "arg0", "指令cmd1.",
38
(arg0) =>
{ Console.WriteLine(String.Format("Invoke cmd1({0}).", arg0)); });
39
cd.AddCmdFunc("cmd2", "arg0 arg1", "指令cmd1.",
40
(arg0, arg1) =>
{ Console.WriteLine(String.Format("Invoke cmd1({0},{1}).", arg0, arg1)); });
41
cd.AddCmdFunc("cmd3",
42
(arg0, arg1, arg2) =>
{ Console.WriteLine(String.Format("Invoke cmd1({0},{1},{2}).", arg0, arg1, arg2)); });
43
return cd;
44
}
45
}
46
}
47
运行结果:

下载代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义