Рисование треугольников в консоли
Изучаю шарп, хотелось бы получить критику и советы как лучше сделать!
Три класса
Program: Мейн класс вызывает классы Rectangle and Triangle.Rectangle: Содержит метод получение площади по двум сторонам.Triangle: Содержит методы вывода в консоль треугольников с помощью*
Код рабочий!
using System.Drawing;
namespace TaskOne
{
class Program
{
static void Main(string[] args)
{
Program app = new Program();
app.StartApplication();
}
public void StartApplication()
{
//getTriangle();
GetRectangle();
}
public void getTriangle()
{
Triangle triangle = new Triangle();
//triangle.ShowTriangle();
//triangle.ShowAnotherTriangle();
triangle.ShowMasTreeTriangle();
}
public void GetRectangle()
{
Rectangle rectangle = new Rectangle();
//rectangle.GetMessage();
rectangle.GetArea();
}
}
}
internal class Rectangle
{
public Rectangle()
{
}
public void GetArea()
{
int firstSide = GetSideLenght();
int secondSide = GetSideLenght();
Console.WriteLine("Площадь прямоугольника: " + (firstSide * secondSide));
}
public int GetSideLenght()
{
Console.Write("Введите длину стороны: ");
int lenght = int.Parse(Console.ReadLine());
if(lenght <= 0)
{
Console.WriteLine("Только положительные числа отличные от нуля,попробуйте снова!");
Environment.Exit(0);
}
return lenght;
}
}
internal class Triangle
{
public Triangle()
{
}
public void ShowTriangle()
{
Console.Write("Введите количество строк: ");
int height = int.Parse(Console.ReadLine());
for (int i = 0; i < height; i++)
{
for (int j = 0; j <= i; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
public void ShowAnotherTriangle()
{
Console.Write("Введите количество строк: ");
int height = int.Parse(Console.ReadLine());
for (int i = 0; i < height; i++)
{
Console.SetCursorPosition(height - i, i + 1);
for (int j = 0; j <= i * 2; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
public void ShowMasTreeTriangle()
{
Console.Write("Введите количество строк: ");
int height = int.Parse(Console.ReadLine());
for (int i = 0; i < height; i++)
{
Console.SetCursorPosition(height - i, i + 1);
for (int j = 0; j <= i * 2; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
}
Ответы (1 шт):
Первое что я заметил, это то что не выполнено условие "игнорировать неверный ввод", в вашем случае приложение падает с исключением FormatException, если пользователь введет не число.
1. Безотказный ввод числа
Чтобы реализовать "безотказный" ввод числе с клавиатуры, я предлагаю создать вот такой вспомогательный класс.
Обратите внимание: в C# проектах принято каждый класс помещать в отдельный файл.
ConsoleHelper.cs
internal static class ConsoleHelper
{
public static int ReadNumber(string prompt, Predicate<int> condition, string errorMessage)
{
int result;
while (true)
{
Console.Write(prompt);
if (int.TryParse(Console.ReadLine(), out result) && condition(result))
break;
Console.WriteLine(errorMessage);
}
return result;
}
}
Данный класс является статическим, потому что ему ничего не надо в себе хранить, и он не взаимодействует с другими внешними нестатическими объектами.
Для одновременной проверки и чтения числа используется метод int.TryParse, который возвращает true, если преобразование строки в int успешно, и false, если нет. В случае успешного преобразования он одновоременно возвращает и само число через out аргумент. Получается 2 в 1.
Из нового и незнакомого здесь используется Predicate<in T>. Предикат - это метод в форме выражения, возвращающего bool (то есть логического выражения), в который передается какой-то аргумент, а нашем случае int. Подробнее о предикатах можно прочитать здесь.
2. Реализация задания
Много кто начинает обучение с консоли, работает со строками, но почему-то мало кто в курсе, что у класса string есть конструкторы, всего 8 перегрузок. В данном случае очень полезной оказалась вот эта перегрузка. Она позволяет создать строку заданной длины, заполненную указанным символом. Это позволит избежать лишних циклов и сделает код проще.
Я переписал классы задания с использованием выше показанного консольного помощника и конструктора string (char c, int count).
Кстати, если конструктор класса пустой, его можно не указывать. Я убрал пустые конструкторы.
Rectangle.cs
internal class Rectangle
{
public void GetArea()
{
const string errorMessage = "Допустимы только положительные числа, попробуйте снова.";
int width = ConsoleHelper.ReadNumber("Введите ширину прямоугольника: ", x => x > 0, errorMessage);
int height = ConsoleHelper.ReadNumber("Введите высоту прямоугольника: ", x => x > 0, errorMessage);
Console.WriteLine("Площадь прямоугольника: {0}", width * height);
}
}
Triangle.cs
internal class Triangle
{
private const string errorMessage = "Допустимы только положительные числа, попробуйте снова.";
public void ShowTriangle()
{
int height = ConsoleHelper.ReadNumber("Введите количество строк: ", x => x > 0, errorMessage);
Console.WriteLine();
for (int i = 1; i <= height; i++)
{
Console.WriteLine(new string('*', i));
}
}
public void ShowAnotherTriangle()
{
int height = ConsoleHelper.ReadNumber("Введите количество строк: ", x => x > 0, errorMessage);
Console.WriteLine();
for (int i = 0; i < height; i++)
{
Console.SetCursorPosition(height - i - 1, Console.CursorTop);
Console.WriteLine(new string('*', i * 2 + 1));
}
}
}
Еще я сделал, чтобы положение курсора в консоли менялось относительно текущей строки, а не абсолютных координат экрана, с помощью свойства консоли CursorTop.
3. Пользовательский интерфейс
Ваше приложение никак не взаимодействует с пользователем. А чтобы изменить используемый метод, нужно редактировать код приложения, и пересобирать само приложение. Это не совсем удобно, или даже не возможно в случае, если пользователь не имеет установленных инструментов разработчика C#.
Для исправления этого, я переписал класс Program, добавил главное меню.
Program.cs
class Program
{
static void Main(string[] args)
{
Program app = new Program();
app.StartApplication();
}
private int MainMenu()
{
string[] menu = new string[]
{
"[1] - Rectangle",
"[2] - Triangle",
"[3] - Another Triangle",
"[0] - Выход",
""
};
Console.WriteLine(string.Join(Environment.NewLine, menu));
return ConsoleHelper.ReadNumber("Ваш выбор: ", x => x >= 0 && x <= 3, "Введите число 0 до 3.");
}
public void StartApplication()
{
Console.WriteLine("Задание 1.1" + Environment.NewLine);
int option;
while ((option = MainMenu()) > 0)
{
Console.WriteLine();
switch (option)
{
case 1:
Rectangle rectangle = new Rectangle();
rectangle.GetArea();
break;
case 2:
Triangle triangle = new Triangle();
triangle.ShowTriangle();
break;
case 3:
triangle = new Triangle();
triangle.ShowAnotherTriangle();
break;
}
Console.WriteLine();
}
}
}
В соответствии с принципом SRP в SOLID, я бы еще вынес меню в отдельный класс, но оставил здесь, чтобы не усложнять пример.
Вывод в консоль:
Задание 1.1
[1] - Rectangle
[2] - Triangle
[3] - Another Triangle
[0] - Выход
Ваш выбор: 1
Введите ширину прямоугольника: 10
Введите высоту прямоугольника: 15
Площадь прямоугольника: 150
[1] - Rectangle
[2] - Triangle
[3] - Another Triangle
[0] - Выход
Ваш выбор: 2
Введите количество строк: 5
*
**
***
****
*****
[1] - Rectangle
[2] - Triangle
[3] - Another Triangle
[0] - Выход
Ваш выбор: 3
Введите количество строк: 8
*
***
*****
*******
*********
***********
*************
***************
[1] - Rectangle
[2] - Triangle
[3] - Another Triangle
[0] - Выход
Ваш выбор: 0
Если что-то забыл объяснить, напишите в комментариях, дополню.
