Оцените качество кода, не знаю как избавиться от дублирования

class MainLoop
{
    static void Main(string[] args)
    {
        Console.Write("Здраствуйте, что вы хотите сделать с файлом? ");
        string action = Console.ReadLine().ToLower();
        Console.Clear();
        switch (action)
        {
            case "создать файл":
                string[] fileInformation = InputFileInformation();
                CreateFile(fileInformation[0], fileInformation[1]);
                Console.WriteLine("Файл успешно создан!");
                break;
            case "удалить файл":
                fileInformation = InputFileInformation();
                File.Delete($"{fileInformation[0]}.{fileInformation[1]}");
                Console.WriteLine("Файл успешно удалён!");
                break;
            default:
                Console.WriteLine($"Извините, но я не понимаю запрос '{action}'.");
                break;
        }

        AskEnterKey();
    }

    static string[] InputFileInformation()
    {
        string fileName = AskInput("Отлично. Введите имя файла: ");
        Console.Clear();
        ShowInputWarning();
        string fileExtension = AskInput("Теперь введите расширение файла: ");
        string[] fileInfo =
        {
            fileName,
            fileExtension
        };
        return fileInfo;
    }

    static void ShowInputWarning()
    {
        Console.SetCursorPosition(0, 20);
        Console.WriteLine("ВАЖНО!!! ВВОД ДОЛЖЕН БЫТЬ БЕЗ ТОЧКИ!!!");
        Console.SetCursorPosition(0, 0);
    }

    static string AskInput(string text)
    {
        Console.Write(text);
        string userInput = Console.ReadLine();
        return userInput;
    }

    static void CreateFile(string name, string extension)
    {
        var file = File.Create($"{name}.{extension}");
        file.Close();
    }

    static void AskEnterKey()
    {
        Console.Write("Нажмите любую клавишу чтобы продолжить . . .");
        Console.ReadKey();
    }
}

Ответы (2 шт):

Автор решения: Dev18

код написан просто и понятно, я предложу несколько изменений.

сам switch-case лучше не загружать, чтобы сразу было видно, что там происходит, поэтому вынесем в отдельные методы действия — удалить и создать. //кстати, у вас уже есть метод create

static void CreateFile(FileInfoInput info)
{
    //тут действия
}

static void DeleteFile(FileInfoInput info)
{
    //тут действия
}

Чтобы не передавать имя и расширение по отдельности, создадим отдельный класс/record FileInfoInput:

record FileInfoInput(string Name, string Extension)
{
    public string FullName => $"{Name}.{Extension}";
}

Также я бы вынесла строковые команды в enum и распарсила в методе ParseCommand:

enum FileCommand
{
    Unknown,
    Create,
    Delete
}

итоговый вариант кода:

class MainLoop
{
    static void Main(string[] args)
    {
        Console.Write("Здравствуйте, что вы хотите сделать с файлом? ");
        var command = ParseCommand(Console.ReadLine());
        Console.Clear();

        //сразу понимаю, идти дальше или остановиться
        if (command == FileCommand.Unknown)
        {
            Console.WriteLine("Извините, я не понимаю ваш запрос.");
            AskEnterKey();
            return;
        }
        //если команда ок, собираем информацию файла
        var info = InputFileInformation(); 
        Console.Clear();

        switch (command)
        {
            case FileCommand.Create:
                CreateFile(info); //тут чище, глазу легче читается
                break;

            case FileCommand.Delete:
                DeleteFile(info); //тоже
                break;
        }

        AskEnterKey();
    }

    static void CreateFile(FileInfoInput info)
    {
        try
        {
            //using автоматически закроет поток, даже если возникнет исключение
            using var file = File.Create(info.FullName);
            Console.WriteLine("Файл успешно создан!");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Ошибка при создании файла: {ex.Message}");
        }
    }

    static void DeleteFile(FileInfoInput info)
    {
        try
        {
            bool existedBefore = File.Exists(info.FullName);

            File.Delete(info.FullName);

            Console.WriteLine(
                existedBefore
                    ? "Файл успешно удалён!" //;)
                    : "Файл не существует."
            );
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Ошибка при удалении файла: {ex.Message}");
        }
    }

    static FileInfoInput InputFileInformation()
    {
        string name = AskInput("Введите имя файла: ");
        Console.Clear();

        ShowInputWarning();
        //лучше показать файл, чтобы юзер видел
        Console.WriteLine($"Имя файла: {name}");
        string extension = AskInput("Введите расширение файла (без точки): ");

        return new FileInfoInput(name, extension);
    }

    static void ShowInputWarning()
    {
        Console.SetCursorPosition(0, 20);
        Console.WriteLine("ВАЖНО: ввод расширения — без точки!");
        Console.SetCursorPosition(0, 0);
    }

    static string AskInput(string text)
    {
        Console.Write(text);
        return Console.ReadLine();
    }

    static void AskEnterKey()
    {
        Console.Write("Нажмите любую клавишу, чтобы продолжить...");
        Console.ReadKey();
    }

    static FileCommand ParseCommand(string input)
    {
        switch (input.ToLower())
        {
            case "создать файл":
                return FileCommand.Create;

            case "удалить файл":
                return FileCommand.Delete;

            default:
                return FileCommand.Unknown;
        }
    }
}

record FileInfoInput(string Name, string Extension)
{
    public string FullName => $"{Name}.{Extension}";
}

enum FileCommand
{
    Unknown,
    Create,
    Delete
}

«Чистый код — это код, который проще читать, чем писать.» Роберт Мартин ? https://www.oreilly.com/library/view/clean-code-a/9780136083238/

→ Ссылка
Автор решения: InterceptorTSK

Весьма просто разделить логику поступающих команд+атрибутов от логики исполнения. И естественно нужно зациклить поступающие команды.

Логика команд+атрибутов вызывает соответствующие делегаты. Код весьма прост, таблица команд и таблица делегатов, и поиск сопоставления.

В конце сами вызываемые методы через команды, естественно без System.IO, иначе код получится размерами с Войну и Мир.

Не делите файл и расширение файла. Потому что сие не формализовано. Т.е. иначе говоря вы не сможете точно определить где файл и его расширение, примеры файлов:

.txt
txt.txt
txt.txt.txt
txt.new.txt
txt.tar.gz

Где тут файлы и расширения файлов - определить весьма проблематично, и не нужно этим заниматься.

@quert123 ваш вопрос на самом деле - архитектурный, точнее микроархитектурный. Это когда код пишется так, что бы можно было легко добавить новый функционал, или изменить/подправить имеющийся. Изучите то что написано ниже, это и есть архитектура. Всяких Мартинов с чистым кодиком никогда не слушайте, ибо код должен быть архитектурным, а грязный он или чистый - это не существенно, ибо всё равно кроме вас никто чейтать не будет. Чистая архитектура важна, а код не существеннен.

static class Program
{
    static void Main(string[] args)
    {
        Do();
    }

    static void Do()
    {
        if (System.Console.IsInputRedirected)
        {
            ConsoleWriteInputRedirectNotSupported();
            return;
        }

        var invariantCulture = System.Globalization.CultureInfo.InvariantCulture;

        // Input Commands
        string[] commands = new string[9]
        {
            "e",
            "h",
            "fcrop",
            "fcr",
            "fop",
            "fsvcl",
            "fsv",
            "fcl",
            "fdl",
        };
        // .. and Delegates
        Operation[] operations = new Operation[9]
        {
            OperationExit,
            OperationHelp,
            OperationFileCreateOpen,
            OperationFileCreate,
            OperationFileOpen,
            OperationFileSaveClose,
            OperationFileSave,
            OperationFileClose,
            OperationFileDelete,
        };
        if (commands.Length != operations.Length)
            throw new System.Exception("commands.Length != operations.Length");

        // Pre-jit all operations
        //PrepareDelegates(operations);

        ConsoleWriteHelp();

        do
        {
            ConsoleWrite();

            // Input line
            string line = System.Console.ReadLine();
            if (line == null || string.IsNullOrWhiteSpace(line)) continue;
            line = line.Trim();

            int lineLength = line.Length;

            // Find Command and do Delegate loop
            for (int i = 0; i < commands.Length; i++)
            {
                if (line.StartsWith(commands[i], true, invariantCulture))
                {
                    int cmdLength = commands[i].Length;

                    if (lineLength == cmdLength)
                    {
                        // Do Delegate without Attribute (Empty)
                        operations[i](string.Empty); break;
                    }
                    if (lineLength >= cmdLength + 1)
                    {
                        if (line[cmdLength] != ' ') break;
                    }

                    string attribute = line.Substring(cmdLength + 1);

                    // Do Delegate with Attribute (not Empty)
                    operations[i](attribute); break;
                }
            }
        }
        while (ExitFlag == false);
    }
    //static void PrepareDelegates(System.Delegate [] delegates)
    //{
    //    if (delegates != null)
    //        for (int i = 0; i < delegates.Length; i++)
    //            if (delegates[i] != null))
    //                System.Runtime.CompilerServices.RuntimeHelpers.PrepareDelegate(delegates[i]);
    //}


    static void ConsoleWriteHelp()
    {
        var sb = new System.Text.StringBuilder(82 * 11, 82 * 11).AppendLine();
        sb.Append("    Usage              Operation           ").AppendLine().AppendLine();
        sb.Append("    e                  Exit                ").AppendLine();
        sb.Append("    h                  This Help           ").AppendLine().AppendLine();
        sb.Append("    fcrop file_path    File Create and Open").AppendLine();
        sb.Append("    fcr   file_path    File Create         ").AppendLine();
        sb.Append("    fop   file_path    File Open           ").AppendLine().AppendLine();
        sb.Append("    fsvcl file_path    File Save and Close ").AppendLine();
        sb.Append("    fsv   file_path    File Save           ").AppendLine();
        sb.Append("    fcl   file_path    File Close          ").AppendLine().AppendLine();
        sb.Append("    fdl   file_path    File Delete         ").AppendLine();
        System.Console.WriteLine(sb);
    }
    static void ConsoleWrite()
    {
        System.Console.Write("Usage>");
    }
    static void ConsoleWriteInputRedirectNotSupported()
    {
        System.Console.WriteLine("Usage>Input Redirect not Supported");
    }
    static void ConsoleWritePathNullOrEmpty()
    {
        System.Console.WriteLine("Usage>Path is Null or Empty");
    }


    // Delegates signature
    delegate void Operation(string attribute);

    static bool ExitFlag = false;
    static void OperationExit(string attribute)
    {
        System.Console.WriteLine("Warn! Release ALL file descriptors here");
        ExitFlag = true;
    }
    static void OperationHelp(string attribute)
    {
        ConsoleWriteHelp();
    }


    static string GetPath(string str)
    {
        string path = null;

        if (str != null && !string.IsNullOrWhiteSpace(str))
            try { path = System.IO.Path.GetFullPath(str); }
            catch { }

        return path;
    }


    static void OperationFileCreateOpen(string attribute)
    {
        string path = GetPath(attribute);
        if (path == null) { ConsoleWritePathNullOrEmpty(); return; }

        OperationFileCreate(attribute);
        OperationFileOpen(attribute);

        System.Console.WriteLine("FILE_CREATE_OPEN \"{0}\"", path);
    }
    static void OperationFileCreate(string attribute)
    {
        string path = GetPath(attribute);
        if (path == null) { ConsoleWritePathNullOrEmpty(); return; }

        System.Console.WriteLine("FILE_CREATE \"{0}\"", path);
    }
    static void OperationFileOpen(string attribute)
    {
        string path = GetPath(attribute);
        if (path == null) { ConsoleWritePathNullOrEmpty(); return; }

        System.Console.WriteLine("FILE_OPEN \"{0}\"", path);
    }
    static void OperationFileSaveClose(string attribute)
    {
        string path = GetPath(attribute);
        if (path == null) { ConsoleWritePathNullOrEmpty(); return; }

        OperationFileSave(attribute);
        OperationFileClose(attribute);

        System.Console.WriteLine("FILE_SAVE_CLOSE \"{0}\"", path);
    }
    static void OperationFileSave(string attribute)
    {
        string path = GetPath(attribute);
        if (path == null) { ConsoleWritePathNullOrEmpty(); return; }

        System.Console.WriteLine("FILE_SAVE \"{0}\"", path);
    }
    static void OperationFileClose(string attribute)
    {
        string path = GetPath(attribute);
        if (path == null) { ConsoleWritePathNullOrEmpty(); return; }

        System.Console.WriteLine("FILE_CLOSE \"{0}\"", path);
    }
    static void OperationFileDelete(string attribute)
    {
        string path = GetPath(attribute);
        if (path == null) { ConsoleWritePathNullOrEmpty(); return; }

        System.Console.WriteLine("FILE_DELETE \"{0}\"", path);
    }
}

result

→ Ссылка