1

Изучаю шарп, хотелось бы получить критику и советы как лучше сделать!

Три класса

  • 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();
    }
}

}

aepot
  • 49,560
  • 3
    Читали описание метки [tag:инспекция-кода]? – dIm0n Aug 27 '20 at 13:40
  • 1
    @dIm0n И что тут не так? – EvgeniyZ Aug 27 '20 at 13:54
  • 1
    @dIm0n может и всё так но я бы хотел узнать как можно сделать лучше если можно – Alex Netton Aug 27 '20 at 13:55
  • 1
    @EvgeniyZ несодержательный заголовок, задание картинками и т.д. (см. описание) – dIm0n Aug 27 '20 at 13:56
  • @AlexNetton прочитайте описание метки и отредактируйте вопрос с помощью кнопки править – dIm0n Aug 27 '20 at 13:57
  • 2
    @dIm0n Ну так подправьте заголовок, если он вам не нравиться. Человек пришел с полностью рабочим кодом, попросил посмотреть, правильно-ли он написал все, может можно иначе, дал задание по которому он это написал, поставил инспецию кода, но нет, получает минусы, за что? Где тут несогласование с инспекцией то? – EvgeniyZ Aug 27 '20 at 13:58
  • Сорри я второй день тут могу делать ошибки – Alex Netton Aug 27 '20 at 13:58
  • @EvgeniyZ я написал конкретные пункты, всё есть по ссылкам https://ru.stackoverflow.com/tags/инспекция-кода/info и [ask] – dIm0n Aug 27 '20 at 14:01
  • @AlexNetton не надо передо мной извиняться :D. Просто улучшите качество вопроса, вот кнопка – dIm0n Aug 27 '20 at 14:02
  • 2
    @dIm0n Я говорю, что если видите косяк, то напишите об этом автору напрямую, либо исправьте сами. Если взять ваш первый комментарий, то совершенно не понятно в чем проблема. Смотрим метку: Наличие реального работающего кода - есть, Содержательный заголовок и Отсутствие избыточных слов в заголовке - есть небольшой косяк, который каждый без труда может исправить. Указание назначения кода - есть, Описание, откуда этот код взялся - думаю это вовсе лишнее. Так как ваш первый комментарий указывает на ошибки в вопросе? Вот сейчас закроют вопрос и? Поймет автор что от него хотят? – EvgeniyZ Aug 27 '20 at 14:11
  • 1
    @EvgeniyZ "Я говорю, что если видите косяк, то напишите об этом автору напрямую, либо исправьте сами. Если взять ваш первый комментарий, то совершенно не понятно в чем проблема." — я и написал ему первым комментарием, это вопрос, а не проблема; "каждый без труда может исправить" — в этом и смысл, чтобы он исправил; "думаю это вовсе лишнее" — предложите правку метки/создайте обсуждение на мете; ответы на следующие три вопроса: 1) это не указание ошибок, а вопрос; 2) будет закрыт, пока не переоткроют; 3) зависит от ТС – dIm0n Aug 27 '20 at 14:23
  • 1
    @dIm0n я и написал ему первым комментарием, это вопрос, а не проблема - с огромным намеком на то, что у него есть "косяк", а какой - пусть сам гадает. в этом и смысл, чтобы он исправил - на SO не просто так у всех есть механизм редактирования. Автор вон исправил по вашим наводкам вопрос, нравиться? предложите правку метки - в описание метке не правила, а рекомендации, зачем вам знать очевидные вещи? Написал автор сам код, и? Вам даст это что либо? пока не переоткроют - тут очень редко переоткрывают. зависит от ТС - и от нас тоже. Короче спорить с вами не буду, парня лишь жалко. – EvgeniyZ Aug 27 '20 at 14:31
  • Коллеги, этой дтскуссии место на мете, она не относится к вопросу. \ – tym32167 Aug 27 '20 at 14:44
  • @EvgeniyZ вот вы пишете "есть небольшой косяк, который каждый без труда может исправить", однако же не исправляете сами .. Что касается закрытия - стоит напомнить, что закрытие - это сначала "требует правки" - явное указание ТС что с вопросом не так и возможность правки-переоткрытия. *некропостинг закончен)) – Kromster Apr 10 '21 at 19:45
  • @Kromster Не работает такая система как "закрытие" и "переоткрытие" на SO! Могу кучу вопросов дать, которые имеют уйму проблем (от дубликатов, до банального "не закрыта скобка"), но чтот их не закрывают (если они только не слишком явные нарушения имеют и не режут дико сообществу глаза). Конкретно в этом случае, человек пришел с нормальным вопросом, попросил помощь, а ему сразу накидали минусов, пытаясь закрыть как "непонятный" (вроде), и вот что тут "непонятного"? Выше вон вообще говорят, что он инспекцию нарушает, только вот где..? Короче, этому вопросу не дали какого-либо шанса изначально. – EvgeniyZ Apr 10 '21 at 22:10
  • @EvgeniyZ система работает, если ей систематически пользоваться. Кучу вопросов можете дать - вы на них на всех правку и/или комментарий и/или минус и/или флаг оставили? ;-) Конкретно про этот вопрос - давайте вместе почитаем описание метки и текст с картинок .. уже достаточно для минуса как мне (и другим) кажется. А шанс - даден, и плюсов отсыпано, и ответ хороший ) – Kromster Apr 11 '21 at 05:23
  • @Kromster если ей систематически пользоваться - Посмотрите мой вопрос на мете, увидите, что большинство людей советуют просто пройти мимо и закрывать на многое глаза, ведь это "хорошо раскрученный форум", где каждый заходит почитать темку после тяжелой работы, без напряга и другой ерунды. Кучу вопросов можете дать - не поверите, на все ставил голос, писал в комментарии, где это уместно, в итоге либо 1 голос висит, либо виси 4 и вопрос не закрывают. Конкретно про этот вопрос - на месте автора, увидев, что вопрос заминусовали, я бы свалил с SO, забыв про него как про ужасную помойку. – EvgeniyZ Apr 11 '21 at 09:04
  • @Kromster Короче, у вас есть своя голова на плечах, у меня своя, у нас с вами свое видение ситуации, а конкретно в этом случае, парня изначально просто заминусовали, без каких-либо объяснений и тут я вам уже сказал выше, на его месте я бы расценил это весьма негативно. И спрашивается, стоило-ли нам так поступать? Может стоило бы объяснить, может как-то поправить вопрос, а не тупо кидать голос и закрывать? В общем, дальше спорить на эту тему не вижу смысла, тем более на SO, где всем на подобное плевать. – EvgeniyZ Apr 11 '21 at 09:08

1 Answers1

2

Первое что я заметил, это то что не выполнено условие "игнорировать неверный ввод", в вашем случае приложение падает с исключением 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(&quot;Площадь прямоугольника: {0}&quot;, width * height);
}

}

Triangle.cs

internal class Triangle
{
    private const string errorMessage = "Допустимы только положительные числа, попробуйте снова.";
public void ShowTriangle()
{
    int height = ConsoleHelper.ReadNumber(&quot;Введите количество строк: &quot;, x =&gt; x &gt; 0, errorMessage);
    Console.WriteLine();

    for (int i = 1; i &lt;= height; i++)
    {
        Console.WriteLine(new string('*', i));
    }
}

public void ShowAnotherTriangle()
{
    int height = ConsoleHelper.ReadNumber(&quot;Введите количество строк: &quot;, x =&gt; x &gt; 0, errorMessage);
    Console.WriteLine();

    for (int i = 0; i &lt; 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[]
    { 
        &quot;[1] - Rectangle&quot;, 
        &quot;[2] - Triangle&quot;, 
        &quot;[3] - Another Triangle&quot;, 
        &quot;[0] - Выход&quot;,
        &quot;&quot;
    };
    Console.WriteLine(string.Join(Environment.NewLine, menu));

    return ConsoleHelper.ReadNumber(&quot;Ваш выбор: &quot;, x =&gt; x &gt;= 0 &amp;&amp; x &lt;= 3, &quot;Введите число 0 до 3.&quot;);
}

public void StartApplication()
{
    Console.WriteLine(&quot;Задание 1.1&quot; + Environment.NewLine);
    int option;
    while ((option = MainMenu()) &gt; 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

aepot
  • 49,560
  • 1
    Тут наверно стоит немного про ООП и прочие базовые принципы упомянуть. Помниться был этот ответ, где было хорошо показано как на примере простого консольного приложения разбить логику на классы и методы с единственной ответственностью. Также switch можно заменить на некую обертку, которая помогла бы сохранить это все в одном месте и вызывать в удобный момент (об этом я как-то писал тут), но это уже зависит как дальше будет развиваться проект, если чисто для сдачи, то switch самое то. – EvgeniyZ Aug 28 '20 at 00:25
  • @EvgeniyZ если вас не затруднит, можете отредактировать ответ, потому что я уже с мобильного, и вернусь в полноценный онлайн не скоро. На SO ужасный мобильный редактор. Про SRP конечно стоит упомянуть, а вот switch я бы оставил как есть. Мне и так кажется, что я перегнул с предикатом, но вменяемого варианта без него не придумал. – aepot Aug 28 '20 at 00:38
  • 1
    Хех, я и сам последнюю неделю с мобильного, так что увы)) Я думаю если автор вопроса увидит хотя бы мой комментарий, то этого будет достаточно для него, по ссылкам есть вся информация. – EvgeniyZ Aug 28 '20 at 00:43
  • @AlexNetton старайтесь все-таки сами решать. Если вам помог мой ответ, отметьте его пожалуйста принятым. Галочка слева от ответа. – aepot Aug 31 '20 at 10:36
  • 1
    @aepot я стараюсь решать сам просто есть моменты про которые я не знаю например как конструкторы стринга фича которую теперь постоянно буду юзать где это уместно) – Alex Netton Aug 31 '20 at 13:05