Как сжать идентичные повторяющиеся утверждения Else If - PullRequest
0 голосов
/ 03 декабря 2018

Я экспериментирую с простыми программами, по которым пользователь может перемещаться с помощью базового ввода 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, если Else заявления повторяются КАЖДЫЙ раз, когда я спрашиваюдля ввода пользователя, а затем проверьте его.Это становится очень тяжелым, поскольку я вкладываю пользовательский ввод несколько раз.

Мой вопрос заключается в том, будет ли способ уплотнить эти повторяющиеся операторы Else If в функцию или отдельный класс, чтобы сэкономить время и (много) места, которое было бы эффективно вставить в ветку If / Else If?

((Бонусные баллы, если бы был способ удержать когда-либо повторяющееся «Else» в конце, которое возвращает «Неверный ввод ", но это не главный вопрос или цель.))

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

Я сделал это немного по-другому при реализации интерфейсов 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);
        }

    }

}

Вот ссылка на полный файл Program.cs .

Я загрузил полную кодовую базу в мой GitHub Repo .

0 голосов
/ 03 декабря 2018

Я обычно пытаюсь рефакторинг в таких случаях, пока я не удовлетворен

повторяется КАЖДЫЙ раз, когда я запрашиваю ввод пользователя, а затем проверяю его

Затем начните с упаковкив функции / методе, поэтому вам нужно поддерживать его только в одном месте

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 для возврата требуемой реализации на основе текущего ввода

Вы можете делать все, что поможет вам организовать и поддерживать этот код позже инет никакого абсолютного ответа на то, как вы должны написать это.Один совет: разработка через тестирование обычно помогает писать более понятный и поддерживаемый код

...