在任何输入(C#)期间随时退出控制台应用程序

时间:2018-09-20 18:59:37

标签: c#

我有一个相对较大的控制台应用程序,具有多个菜单和用户输入。我需要为用户创建一种基本上随时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”的选项。

2 个答案:

答案 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 来注入接口实现,您将获得以下优势:

  • 您可以使应用程序可测试-您可以在测试视图中插入播放提示和记录答案的测试视图,从而可以测试自己的逻辑
  • 您可以拥有一个 ResponseFileView ,它允许您接受包含问题答案的“响应文件”,从而实现UI的自动化

您可能想从上面的内容中扩展接口的定义(可能在默认的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,您可以找到相对的答案。