Оцените качество кода, не знаю как избавиться от дублирования
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 шт):
код написан просто и понятно, я предложу несколько изменений.
сам 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/
Весьма просто разделить логику поступающих команд+атрибутов от логики исполнения. И естественно нужно зациклить поступающие команды.
Логика команд+атрибутов вызывает соответствующие делегаты. Код весьма прост, таблица команд и таблица делегатов, и поиск сопоставления.
В конце сами вызываемые методы через команды, естественно без 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);
}
}
