我有一个相对较大的控制台应用程序,具有多个菜单和用户输入。我需要为用户创建一种基本上随时break;
当前进行中的方法“退出”或“返回”的方法。我考虑过使用一堆条件,但这会花费一些时间,而且不是很干净。有什么方法可以持续检查“ Q”是否退出并在整个项目中基于该输入运行方法?
伪代码
我现在所拥有的:
UserInput #1;
UserInput #2;
UserInput #3; //ETC....
PromptFor Quit; //Option to quit after inputs are completed.
我对尝试的想法:
UserInput #1;
PromptFor Quit#1; //Add prompt to quit after every input as a conditional.
UserInput #2;
PromptFor Quit#2;
UserInput #3;
PromptFor Quit#3;
我想要拥有的东西:
PromptForQuit //Some method of constantly checking if userInput hit's "Q" or "ESC" key is entered.
{
UserInput#1;
UserInput#2;
UserInput#3; // etc..
}
我可以通过将其硬编码为每种方法来解决它,但是必须有一种更好的方法来实现。另外,我需要向控制台输出每个输入都可以退出“ Q”的选项。
答案 0 :(得分:1)
自90年代初以来,我还没有做过复杂的控制台应用程序。如果我有一个带有“具有多个菜单和用户输入”的应用程序,那么我通常会使用某些本身支持该功能的东西(Windows窗体,WPF,Web应用程序)。但是...
如果这是一个足够大/复杂的项目,尤其是如果您打算编写其中一个以上的项目,那么可能有必要编写一个基于“模型-视图-控制器(MVC)”模式的小框架。
在这种情况下,我们实际上有两个模型,一个模型描述程序流程相当复杂,另一个模型是包含用户答案的简单Dictionary
。 Controller是一个简单的处理循环,可以在第一个模型中执行指令。视图非常简单,但是通过将其分离出来,可以看到一些优点。
为此,您将需要完全更改编程的结构。我假设它主要是这样的:
Console.WriteLine("UserInput #1");
var response = Console.ReadLine();
DoSomethingWith(response);
Console.WriteLine("UserInput #2");
response = Console.ReadLine();
DoSomethingWith(response);
// lather, rinse, repeat
相反,程序的流程将由该第一个模型确定。所以...
第一个模型是重要的部分,但让我们先将第二个模型弄清楚。第二个模型( AnswerModel )只是一个List<Answer>
,其中一个Answer
类似于:
public class Answer {
public string StepName { get; set; }
public string VerbatimResponse { get; set; }
public object TypedResponse { get; set; }
public Type ResponseType { get; set; }
}
它代表对特定问题的答案。答案列表表示到目前为止所有用户问题的答案。可能可以玩一些泛型游戏(可能具有继承性),以使TypedResponse
属性实际上得到正确键入,这应该足以使我们入门。
第一个模型 InputModel 是程序的内胆。它由ModelStep
个对象的集合组成。该集合可能只是一个简单的列表(问题1,问题2等),也可能是一个复杂的图形。尤其是,下面显示的模型中的EvalNextStep
委托属性使您可以构建一个简单的状态机(例如,如果您的问题之一是“您的性别是什么?”,则可以通过另外一条路径男性和女性的图表。
InputModel看起来像这样(您可以根据需要进行调整):
public class ModelStep {
public string StepName { get; set; }
public string Prompt { get; set; }
public bool IsOptional {get; set;}
public UserInputType InputType { get; set; }
public TypeValidator BasicValidator { get; set; }
public SpecificValidator AdditionalValidator { get; set; }
public Action <List<Answer>, string> AfterInputAction { get; set; }
public Func<List<Answer>, string, string> EvalNextStep { get; set; }
}
StepName属性是所有内容的键(请注意,它对应于AnswerModel的StepName属性)。提示是提示答案时将使用的提示。我不确定是否需要UserInputType
属性,但我设想它看起来像:
public enum UserInputType {
String,
Integer,
Numeric,
Enum,
}
两个验证器用于验证用户输入。 TypeValidator
类可能是abstract
,其中包含具体的子类,例如:
StringValidator
IntegerValidator
DoubleValidator
EnumValidator<T> where T : enum
TypeValidator在活动中的作用是获取用户的输入,验证其是否为正确的类型,然后以正确类型的对象形式返回错误消息或响应。
SpecificValidator
对象将进行其他验证。 SpecificValidator
也可能是abstract
类,其具体子类如下:
LessThanValidator<T> where T : IComparable
GreaterThanValidator<T> where T : IComparable
RangneValidator<T> where T : IComparable
AdditionalValidator
属性是可选的。如果需要,它将提供其他验证。如果验证失败,它将返回错误消息。
AfterInputAction
委托可以有选择地指向一个函数,该函数获取到目前为止的所有答案和当前步骤的名称,并在需要时对这些信息进行处理。
EvalNextStep
委托将接受与AfterInputAction
委托相同的输入,并返回“下一步”运行。如上所述,这将允许您创建一个简单的“状态机”。您可能不需要它,但可能会使它变得有趣。
控制器是程序的核心,但它确实很简单。在程序开始时,您将为控制器提供 InputModel 以及指示第一步的内容,控制器将仅遍历InputModel集合,提示用户并征求响应。
但是,由于所有用户交互都集中在一个地方,因此轻松实现“退出”功能。您还可以实现其他类似功能,例如:
同样,由于所有交互都在同一代码中,因此您可以轻松地就允许使用哪些命令(退出,返回等)提供某种一致的指示。
诱惑是使控制器使用Console.WriteLine,Console.ReadLine等直接与控制台交互。
但是,将其抽象为 View 并使用interface
定义View有一些好处。像这样:
public interface IConsoleView {
void Write(string stringToWrite);
void WriteLine(string stringToWrite);
string ReadLine(string prompt);
}
使用Console类可以轻松创建此接口的默认实现。但是,通过使其成为接口并使用 Dependency Injection 来注入接口实现,您将获得以下优势:
您可能想从上面的内容中扩展接口的定义(可能在默认的Console
类实现中具有多余功能的不做任何实现)。例如:
void WriteStepName(string stepName);
void WriteUserResponse (string userResponse);
类似的功能在测试和响应文件方案中可能很有用。您将在普通视图中提供空的实现。
抱歉,这种情况持续了一段时间,但我在最后一天左右一直在考虑。无论您做什么,都不要尝试使用其他线程来执行此操作,这只会使您头痛。
答案 1 :(得分:0)
简单答案::只需随时使用ctrl + C
退出控制台(无需代码)
如果您想在存在之前进行一些清理操作:,那么您可能正在寻找Console.CancelKeyPress Event
private static volatile bool cancelRequested = false;
public static void Main(string[] args)
{
Console.CancelKeyPress += new ConsoleCancelEventHandler(ExitConsole);
while (!cancelRequested)
{
// here your program will continue a WHOLE WHILE loop until user requests exit by
// pressing either the C console key (C) or the Break key
// (Ctrl+C or Ctrl+Break).
UserInput #1;
UserInput #2;
UserInput #3;
}
}
static void ExitConsole(object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
cancelRequested = true;
}
Here,您可以找到相对的答案。