在任何输入(C#)期间随时退出控制台应用程序 [英] Exit Console App at any Time During Any Input (C#)

查看:32
本文介绍了在任何输入(C#)期间随时退出控制台应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个相对较大的控制台应用程序,具有多个菜单和用户输入.我需要为用户创建一种随时随时退出或退出的方法,基本上是 break; 当前进行中的方法.我考虑过使用一堆条件,但这会花费一些时间,而且不是很干净.有什么方法可以持续检查"Q"是否退出并在整个项目中基于该输入运行方法?

I have a relatively large console app with multiple menu's and user inputs. I need to create a way for a user to "Quit" or "Back" at any time essentially break; the current method in progress. I considered using a whole bunch of conditionals but that would take some time and wouldn't be very clean. Is there any way to continually check for "Q" to quit and run a method based on that input across an entire project?

伪代码

我现在所拥有的:

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"的选项.

I could solve it by hard-coding it into every single method but there has to be a better way to do it. Also, I need to output to the console that there is an option to "Q" to quit for every input.

推荐答案

自90年代初以来,我还没有做过复杂的控制台应用程序.如果我有一个带有具有多个菜单和用户输入"的应用程序,那么我通常会使用某些本身支持该功能的东西(Windows窗体,WPF,Web应用程序).但是...

I haven't done a complex console application since the early 90s. If I have an app with "with multiple menu's and user inputs", I usually use something (Windows Forms, WPF, a web app) that supports that natively. But...

如果这是一个足够大/复杂的项目,尤其是如果您打算编写其中一个以上的项目,那么可能有必要编写一个基于模型-视图-控制器(MVC)"模式的小框架.

If this is a big/complex enough project, and particularly if you have plans to write more than one of these, it might be worth writing a little framework based on the Model-View-Controller (MVC) pattern.

在这种情况下,我们实际上有两个模型,一个模型描述程序流程相当复杂,另一个模型是包含用户答案的​​简单 Dictionary .Controller是一个简单的处理循环,可以在第一个模型中执行指令.该视图非常简单,但是通过将其分离出来,我们将看到一些优势.

In this case, we'll actually have two models, one that's reasonably complex that describes the program flow, and a second one that is a simple Dictionary that contains the user's answers. The Controller is a simple processing loop that executes the directives in the first model. The View is very simple, but we'll see that by segregating it out, there are some advantages.

为此,您将需要完全更改编程的结构.我假设它主要是这样的:

To do this, you will need to completely change the structure of your programming. I'm assuming it mostly looks like this:

 Console.WriteLine("UserInput #1");
 var response = Console.ReadLine();
 DoSomethingWith(response);
 Console.WriteLine("UserInput #2");
 response = Console.ReadLine();
 DoSomethingWith(response);
 // lather, rinse, repeat

相反,程序的流程将由该第一个模型确定.所以...

Instead, the flow of the program will be determined by that first model. So...

第一个模型是重要的部分,但让我们先将第二个模型弄清楚.第二个模型( AnswerModel )只是一个 List< Answer> ,其中 Answer 类似于:

The first model is the important part, but let's get the second model out of the way first. The second model (the AnswerModel) is just a List<Answer>, where an Answer looks something like:

public class Answer {
    public string StepName { get; set; }
    public string VerbatimResponse { get; set; }
    public object TypedResponse { get; set; }
    public Type ResponseType { get; set; }
}

它代表对特定问题的答案.答案列表表示到目前为止所有用户问题的答案.可能可以玩一些泛型游戏(可能具有继承性)来真正正确地键入 TypedResponse 属性,这足以让我们入门.

It represents the answer to a particular question. The List of answers represents the answers to all of the user's questions so far. It may be possible to play some generics games (likely with inheritance) to make the TypedResponse property actually be properly typed, this should be enough to get us started.

第一个模型 InputModel 是程序的内胆.它由 ModelStep 对象的集合组成.该集合可能只是一个简单的列表(问题1,问题2等),也可能是一个复杂的图形.特别是,通过下面显示的模型中的 EvalNextStep 委托属性,您可以构建一个简单的状态机(例如,如果您的问题之一是您的性别是什么?",男性和女性通过图表的单独路径.

The first model, the InputModel is the guts of the program. It will consist of a collection of ModelStep objects. The collection could just be a simple list (question 1, question 2, etc.) or it could be a complex graph. In particular, the EvalNextStep delegate property in the model shown below allows you to build a simple state machine (for example, if one of your questions is "What is your gender?", they you could have a separate path through the graph for males and for females).

InputModel看起来像这样(您可以根据需要进行调整):

The InputModel would look something like this (you could adapt this for your needs):

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 属性,但是我认为它看起来像这样:

The StepName property is the key to everything (note that it corresponds to the StepName property of the AnswerModel). The prompt is the prompt you will use when prompting for an answer. I'm not sure if a UserInputType property is needed, but I envision it to look something like:

public enum UserInputType {
    String,
    Integer,
    Numeric,
    Enum,
}

两个验证器用于验证用户输入. TypeValidator 类很可能是 abstract ,其中包含具体的子类,例如:

The two Validators are used to validate the user input. The TypeValidator class would likely be abstract with concrete subclasses like:

  • StringValidator
  • IntegerValidator
  • DoubleValidator
  • EnumValidator< T>其中T:枚举

TypeValidator在活动中的作用是获取用户的输入,验证其是否为正确的类型,然后以正确键入的对象的形式返回错误消息或响应.

A TypeValidator's role in live is to take the user's input, validate that it's the proper type, and then return either an error message or the response as a properly typed object.

SpecificValidator 对象将执行其他验证. SpecificValidator 也可能是 abstract 类,其具体子类如下:

SpecificValidator objects would do additional validation. SpecificValidator is also likely an abstract class, with concrete subclasses like:

  • LessThanValidator< T>其中T:IComparable
  • GreaterThanValidator< T>其中T:IComparable
  • RangneValidator< T>其中T:IComparable

AdditionalValidator 属性是可选的.如果需要的话,它将提供额外的验证.如果验证失败,它将返回错误消息.

The AdditionalValidator property is optional. It would provide additional validation if it was needed. It would return an error message if the validation failed.

AfterInputAction 委托可以有选择地指向一个函数,该函数可以获取到目前为止的所有答案和当前步骤的名称,并在需要时对这些信息进行处理.

The AfterInputAction delegate would optionally point to a function that takes all of the answers so far and the current step name, and do something with that information if needed.

EvalNextStep 委托将接受与 AfterInputAction 委托相同的输入,并返回下一步"运行.如上所述,这将允许您创建一个简单的状态机".您可能不需要它,但可能会使它变得有趣.

The EvalNextStep delegate would take the same inputs as AfterInputAction delegate and return the "next step" to run. As noted above, this would allow you to create a simple "state machine". You may not need this, but it could make it interesting.

控制器是程序的核心,但它确实很简单.在程序开始时,您将为控制器提供 InputModel 以及指示第一步的内容,控制器将简单地遍历InputModel集合,提示用户并征求响应.

The controller is the meat of the program, but it's real simple. At the start of your program, you'd hand the controller the InputModel and something that indicates the first step, and the controller would simply walk through the InputModel collection, prompting users and soliciting responses.

但是,由于所有用户交互都集中在一个地方,因此轻松实现退出"功能.您还可以实现其他类似功能,例如:

However, since all user interaction is in one place, it would be easy to implement your "Quit" feature. You could also implement other similar features, like:

  • 返回(返回上一个问题并查看您的答案.您可以构建返回堆栈",并允许用户多次返回).
  • 前进(如果有人使用后退",则允许他们前进-可能带有前进堆叠")
  • 跳过(如果问题是可选的,则用户可以跳过该问题)

同样,由于所有交互都在同一代码中,因此您可以轻松地就允许使用哪些命令(退出,返回等)提供某种一致的指示.

Again, since all the interaction is in the same code, you could easily provide some sort of consistent indication as to which of these commands (Quit, Back, etc.) was allowed.

诱惑在于使控制器使用Console.WriteLine,Console.ReadLine等直接与控制台进行交互.

The temptation is to have the controller directly interact with the console using Console.WriteLine, Console.ReadLine, etc.

但是,将其抽象为 View 并使用 interface 定义View有一些好处.像这样:

However, there is some advantage to abstracting this into a View and defining the View using an interface. Something like:

public interface IConsoleView {
    void Write(string stringToWrite);
    void WriteLine(string stringToWrite);
    string ReadLine(string prompt);
}

使用Console类可以轻松创建此接口的默认实现.但是,通过使其成为接口并使用 Dependency Injection 来注入接口实现,您将获得以下优势:

The default implementation of this interface would be braindead easy to create using the Console class. However, by making it an interface and using Dependency Injection to inject an interface implementation, you get several advantages:

  • 您可以使应用程序可测试-您可以在测试视图中插入播放提示和记录答案的测试视图,从而可以测试自己的逻辑
  • 您可以拥有一个 ResponseFileView ,该文件可以让您接受包含问题答案的响应文件",从而实现UI的自动化
  • You make your app testable - you could inject in a test View that played prompts and recorded answers, allowing you to test your logic
  • You could have a ResponseFileView that allow you to accept a "response file" that consists of the answers to the questions, allowing automation of your UI
  • etc.

您可能想从上面的内容中扩展接口的定义(可能在默认的 Console 类实现中具有多余功能的不做任何实现).例如:

You might want to extend the definition of the interface from what I have above (possibly having do-nothing implementations of the extra functions in your default Console class implementation). For example:

void WriteStepName(string stepName);
void WriteUserResponse (string userResponse);

类似的功能在测试和响应文件方案中可能很有用.您将在普通视图中提供空的实现.

Functions like these might be useful in the test and response file scenarios. You would provide empty implementations in the normal view.

抱歉,这种情况持续了一段时间,但我在最后一天左右一直在考虑.无论您做什么,都不要尝试使用其他线程来执行此操作,这只会使您头痛.

Sorry this went on a for a while, but I've been thinking about it the last day or so. Whatever you do, don't try to do this with additional threads, that will just cause you headaches.

这篇关于在任何输入(C#)期间随时退出控制台应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆