我正在构建一个控制台应用程序,以帮助解决我经常做的一些事情。我有一个包含4个程序选项的菜单,可以转换为我班级的不同方法。
基本上它有点像这样:
你想做什么?
1这件事
2那件事
3一些东西
4 Cool Stuff
0所有的东西。
输入命令字符串:_
目前我正在检查有效输入:
while (command.IndexOfAny("12340".ToCharArray()) == -1)
{
//Display the menu and accept input
}
然后用:
控制流程if (command.IndexOf("1") > 0 )
{
thisThing();
}
if (command.IndexOf("2") > 0 )
{
thatThing();
}
if (command.IndexOf("3") > 0 )
{
someStuff();
}
if (command.IndexOf("4") > 0 )
{
coolStuff();
}
if (command.IndexOf("0") > 0 )
{
thisThing();
thatThing();
someStuff();
coolStuff();
}
目标是提供输入并按指示运行一个或多个流程:
1:thisThing()
13:thisThing()和someStuff();
42:thatThing()和coolStuff();
0:运行我定义的所有进程。
有没有办法用更好的做法做这样的事情?
答案 0 :(得分:1)
我会创建一个委托词典。字典键将是输入值,委托将执行代码。
这里涵盖了语法C# Store functions in a Dictionary。
这样你可以在循环中逐步输入字符串并进行字典查找;如果值存在则执行委托,否则跳过。
虽然我发现它更具吸引力和可扩展性,但它并不比if else if endif更好。
答案 1 :(得分:1)
我会创建一个Dictionary<char, DoSomething>
public delegate void DoSomething();
Dictionary<char, DoSomething> commands = new Dictionary<char, DoThing>();
commands.Add('0', new DoSomething(DoAll));
commands.Add('1', new DoSomething(ThisThing));
commands.Add('2', new DoSomething(ThatThing));
commands.Add('3', new DoSomething(SomeStuff));
commands.Add('4', new DoSomething(CoolStuff));
然后,在输入验证后
foreach(char c in command.ToCharArray())
{
// Better check if the input is valid
if(commands.ContainsKey(c))
commands[c].Invoke();
}
字典包含允许的字符作为键,并且作为值包含具有void返回且没有参数的函数的委托。现在只需要通过char循环输入char并调用关联的方法。
请注意,这种方法很少,只需要一个简单的 if / else if / else 或 switch / case 。同样通过这种方式,您的用户可以键入24
或42
来反转方法的执行顺序,这在您的真实环境中是不允许的。
答案 2 :(得分:1)
基于Ayende Rahien project中的正则表达式,我找到了一种非常好的方法来解析Freedb.org数据文件的内容
基本上parser设置了Tuple<Regex, Action<contextual class>>
的列表,其中上下文类会根据解析器当时的位置而更改。解析然后尝试将每个元素(在本例中为行)与正则表达式匹配,并在匹配时执行相应的操作。
在您的情况下,您可以将命令链接到多个输入,例如
public class Parser
{
readonly List<Tuple<Regex, Action>> actions = new List<Tuple<Regex, Action>>();
public Parser()
{
Add(@"^0$", () => { DoSomething(); });
Add(@"^DoSomething$", () => { DoSomething(); });
Add(@"^1$", () => { DoSomethingElse() });
Add(@"^DoSomethingElse$", () => { DoSomethingElse() });
// etc
}
private void Add(string regex, Action action)
{
var key = new Regex(regex, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
actions.Add(Tuple.Create(key, action));
}
public void Parse(string text)
{
foreach (var action in actions)
{
var collection = action.Item1.Matches(text);
try
{
action.Item2();
}
catch (Exception e)
{
// log?
throw;
}
}
}
}
允许您使用不同的输入运行所需的方法。
答案 3 :(得分:0)
我创建了一个接口,所有命令都是从这个接口派生出来的,并且有一个switch语句决定要执行哪个动作。 有些东西......
public abstract class ISystem
{
public abstract void DoSomething();
}
public class ThisThing : ISystem
{
public override void DoSomething()
{
Console.WriteLine("Do This Thing");
}
}
public class ThatThing : ISystem
{
public override void DoSomething()
{
Console.WriteLine("Do That Thing");
}
}
static void Main(string[] args)
{
var input = "-1";
while(/*input is invalid*/)
{
// get input from user
}
var thisThing = new ThisThing();
var thatThing = new ThatThing();
switch(input)
{
case "1":
{
thisThing.DoSomething();
break;
}
case "2":
{
thatThing.DoSomething();
break;
}
case "0":
{
var commands = new List<ISystem>();
commands.Add(thisThing);
commands.Add(thatThing);
// Execute all commands
commands.ForEach(system => system.DoSomething());
break;
}
}
}
这里的优点是每次添加一个新命令时,它只需要实现DoSomething()
方法,之后它只是创建类{{1}的实例的简单任务然后添加到var someStuff = new SomeStuff();
加上IMO的意图比管理词典等更清楚。