我正在尝试一些简单的程序,用户可以使用基本的ReadLine输入进行导航。在输入过程中的任何给定时间,无论环境如何,总是可以访问几个命令,这是一个示例:
else if(input.ToLower() == "exit" || input.ToLower() == "leave")
{
Console.Clear();
ExitProgram.ExitProg();
calcInput = false;
}
else if(input.ToLower() == "back" || input.ToLower() == "menu")
{
TxtFun.CTxt("Returning to previous menu.");
Console.ReadLine();
Console.Clear();
calcInput = false;
calcLoop = false;
}
else
{
TxtFun.CTxt("Invalid input.");
Console.ReadLine();
Console.Clear();
calcInput = false;
}
以上是2如果每次都重复其他语句,则要求用户输入,然后进行检查。当我多次嵌套用户输入时,这会变得很沉重。
我的问题是,是否有一种方法可以将这些重复的其他If语句压缩为一个函数或一个单独的类,以节省时间和(大量)空间,那么将其有效地插入If /如果是其他分支?
(((如果有一种方法可以在返回“无效输入”的末尾包含重复出现的“其他”,但这不是主要问题或目标,则奖励点))
答案 0 :(得分:2)
在实现REPL接口时,我做了一些不同的事情。
使用Dictionary<string, Func<string, string>>
(实际上,我使用的类封装了实际的Func
或Action
以及一个描述,该描述可用于帮助应用程序的可用性生成带有字符串比较的help
文本),该字符串忽略大小写并将期望的输入添加到字典中,其中对象是您要执行的函数。
这也将成为自我文档,您也将能够自动创建帮助文档!
如果您愿意,我明天可以快速发布一个示例。 -在下面添加代码示例的关键部分(来自Program.cs文件):
我们将用于捕获REPL命令信息的类:
class ReplCommand
{
public string Command { get; set; }
public string HelpText { get; set; }
public Action<string> MethodToCall { get; set; }
public int HelpSortOrder { get; set; }
}
这是我们定义所有有效命令的地方
static void PopulateCommands()
{
// Add your commands here
AddCommand(new ReplCommand
{
Command = "MyCommand", // The command that the user will enter (case insensitive)
HelpText = "This is the help text of my command", // Help text
MethodToCall = MyCommand, // The actual method that we will trigger
HelpSortOrder = 1 // The order in which the command will be displayed in the help
});
// Default Commands
AddCommand(new ReplCommand
{
Command = "help",
HelpText = "Prints usage information",
MethodToCall = PrintHelp,
HelpSortOrder = 100
});
AddCommand(new ReplCommand
{
Command = "quit",
HelpText = "Terminates the console application",
MethodToCall = Quit,
HelpSortOrder = 101
});
}
static void AddCommand(ReplCommand replCommand)
{
// Add the command into the dictionary to be looked up later
_commands.Add(replCommand.Command, replCommand);
}
这是程序的关键部分:
// The dictionary where we will keep a list of all valid commands
static Dictionary<string, ReplCommand> _commands = new Dictionary<string, ReplCommand>(StringComparer.CurrentCultureIgnoreCase);
static void Main(string[] args)
{
// Create Commands
PopulateCommands();
// Run continuously until "quit" is entered
while (true)
{
// Ask the user to enter their command
Console.WriteLine("Please input your command and hit enter");
// Capture the input
string sInput = Console.ReadLine();
// Search the input from within the commands
if (_commands.TryGetValue(sInput, out ReplCommand c))
{
// Found the command. Let's execute it
c.MethodToCall(sInput);
}
else
{
// Command was not found, trigger the help text
PrintHelp(sInput);
}
}
}
上面定义的每个注释的具体实现:
static void MyCommand(string input)
{
Console.WriteLine($"MyCommand has been executed by the input '{input}'");
}
static void PrintHelp(string input)
{
// Unless the input that got us here is 'help', display the (wrong) command that was
// entered that got us here
if (input?.ToLowerInvariant() != "help")
{
// Display the wrong command
Console.WriteLine($"Command '{input}' not recognized. See below for valid commands");
}
// Loop through each command from a list sorted by the HelpSortOrder
foreach (ReplCommand c in _commands.Values.OrderBy(o => o.HelpSortOrder))
{
// Print the command and its associated HelpText
Console.WriteLine($"{c.Command}:\t{c.HelpText}");
}
}
static void Quit(string input)
{
System.Environment.Exit(0);
}
}
}
这里是指向complete Program.cs file的链接。
我已将完整的代码库上传到我的GitHub Repo中。
答案 1 :(得分:0)
在这种情况下,我通常会尝试调味,直到满意为止
我每次要求用户输入然后检查它时重复
然后将其包装在函数/方法中,这样您只需要将其维护在一个地方
private void ProcessInput(string input)
{
if(string.IsNullOrEmpty(input)) throw new ArgumentException();
input = input.Trim().ToLower();
if(input == "exit" || input == "leave")
{
Console.Clear();
ExitProgram.ExitProg();
calcInput = false;
}
else if(input == "back" || input == "menu")
{
TxtFun.CTxt("Returning to previous menu.");
Console.ReadLine();
Console.Clear();
calcInput = false;
calcLoop = false;
}
else
{
TxtFun.CTxt("Invalid input.");
Console.ReadLine();
Console.Clear();
calcInput = false;
}
}
然后重构每个if
块...
private void ProcessExitInput(string input)
{
if(input == "exit" || input == "leave")
{
Console.Clear();
ExitProgram.ExitProg();
calcInput = false;
}
}
private void ProcessMenuInput(string input)
{
if(input == "back" || input == "menu")
{
TxtFun.CTxt("Returning to previous menu.");
Console.ReadLine();
Console.Clear();
calcInput = false;
calcLoop = false;
}
}
private void ProcessDefaultInput(string input)
{
if(input != "back" && input != "menu" && input != "exit" && input != "leave")
{
TxtFun.CTxt("Returning to previous menu.");
Console.ReadLine();
Console.Clear();
calcInput = false;
calcLoop = false;
}
}
现在您的ProcessInput
方法变得更小...
private void ProcessInput(string input)
{
if(string.IsNullOrEmpty(input)) throw new ArgumentException();
input = input.Trim().ToLower();
ProcessExitInput(input);
ProcessMenuInput(input);
ProcessDefaultInput(input);
}
您甚至可以使用switch
/ case
块代替if
/ else
块。甚至将if
条件重构为一个单独的对象...
class InputHandler
{
public static bool IsExitInput(string input)
{
return input == "exit" || input == "leave";
}
}
您还可以创建一个InputFactory
对象,该对象根据特定条件(IInputProcessor
)返回特定的input
接口实现。像...
public interface IInputProcessor
{
void Process();
}
public class ExitInputProcessor : IInputProcessor
{
public void Process()
{
//process the exit command input
}
}
并制作一个InputFactory
对象以根据当前输入返回所需的实现
您可以做任何有助于您稍后组织和维护该代码的事情,并且对如何编写代码没有绝对的答案。 一个提示,测试驱动的开发通常有助于编写更清晰和可维护的代码