Основы C#

Ввод и вывод в консоль на C#

Обновлено: · 6 мин чтения

Консольное приложение общается с пользователем через класс Console: методы Write и WriteLine выводят текст, а ReadLine и ReadKey принимают ввод с клавиатуры. Ниже разобраны все основные приёмы: преобразование введённой строки в число, безопасный TryParse, форматированный вывод и работа с цветами консоли.

Ввод и вывод в консоль на C#
Содержание
  1. Вывод текста: Write и WriteLine
  2. Форматированный вывод и интерполяция
  3. Чтение строки: Console.ReadLine
  4. Преобразование ввода в число: Parse и Convert
  5. Безопасный ввод с TryParse
  6. Чтение клавиши: Console.ReadKey
  7. Цвета и оформление консоли
  8. Вывод ошибок и перенаправление потоков
  9. Типичные ошибки
  10. Частые вопросы

Вывод текста: Write и WriteLine

Класс Console находится в пространстве имён System, а в проектах .NET 6 и новее оно подключено автоматически. Метод Console.WriteLine печатает значение и переводит курсор на новую строку, Console.Write оставляет курсор в конце напечатанного текста. Оба метода принимают значения любых типов и сами вызывают ToString.

Console.WriteLine("Привет, мир!");
Console.Write("Сумма: ");
Console.Write(2 + 3);
Console.WriteLine();            // пустая строка
Console.WriteLine(3.14);
Console.WriteLine(true);
Console.WriteLine("Табуляция:\tтекст\nНовая строка");

В строках можно использовать управляющие последовательности: \n для переноса, \t для табуляции, \" для кавычки и \\ для обратной косой черты. Если в консоли вместо русских букв видны знаки вопроса, задайте кодировку вывода в начале программы.

Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.InputEncoding = System.Text.Encoding.UTF8;

Форматированный вывод и интерполяция

Склеивать текст с переменными через плюс неудобно. Проще использовать интерполяцию строк: перед открывающей кавычкой ставится символ доллара, а значения подставляются в фигурных скобках. После двоеточия можно указать формат числа или даты.

string name = "Мария";
int age = 25;
decimal price = 1499.5m;

Console.WriteLine($"{name}, вам {age} лет");
Console.WriteLine($"Цена: {price:F2} руб.");
Console.WriteLine($"Цена: {price:N0}");
Console.WriteLine($"Доля: {0.256:P1}");              // 25,6 %
Console.WriteLine($"Сегодня: {DateTime.Now:dd.MM.yyyy HH:mm}");
Console.WriteLine("{0} - {1}", "Ключ", "Значение");   // составное форматирование

Для выравнивания столбцов указывают ширину поля через запятую: положительное число прижимает значение вправо, отрицательное - влево. Так можно вывести аккуратную таблицу без сторонних библиотек.

Console.WriteLine($"{"Товар",-12}{"Кол-во",6}{"Цена",10}");
Console.WriteLine($"{"Хлеб",-12}{2,6}{45.5,10:F2}");
Console.WriteLine($"{"Молоко",-12}{1,6}{89.9,10:F2}");

Подробнее о методах работы с текстом и форматами рассказано в статье про объявление переменных, где разобраны типы значений, которые чаще всего выводят на экран.

Чтение строки: Console.ReadLine

Метод Console.ReadLine ждёт, пока пользователь введёт текст и нажмёт Enter, и возвращает введённое как строку. Возвращаемый тип - string?, так как при закрытом потоке ввода (например, при нажатии Ctrl+Z в Windows) метод вернёт null. Пока вводится только текст, проблем нет.

Console.Write("Как вас зовут? ");
string? name = Console.ReadLine();

if (string.IsNullOrWhiteSpace(name))
    name = "гость";

Console.WriteLine($"Здравствуйте, {name}!");

Обратите внимание: всё, что вернул ReadLine, - это строка. Даже если пользователь ввёл 42, программа получит текст "42", и складывать такие значения как числа нельзя. Строка "2" плюс строка "3" даст "23". Для арифметики ввод нужно превратить в число.

Преобразование ввода в число: Parse и Convert

Самый простой способ - метод Parse нужного типа: int.Parse, double.Parse, decimal.Parse. Он принимает строку и возвращает число, но выбрасывает исключение FormatException, если строка не подходит, и ArgumentNullException, если пришёл null.

Console.Write("Введите первое число: ");
int a = int.Parse(Console.ReadLine()!);
Console.Write("Введите второе число: ");
int b = int.Parse(Console.ReadLine()!);

Console.WriteLine($"{a} + {b} = {a + b}");

Есть и класс Convert с методами ToInt32, ToDouble и другими. Он отличается тем, что для null возвращает ноль, но для текста вроде "abc" тоже выбросит исключение. Для вещественных чисел внимательно следите за разделителем: в русской региональной настройке дробная часть отделяется запятой, а в инвариантной - точкой. Другие способы смены типа разобраны в материале про приведение типов.

Безопасный ввод с TryParse

Пользователь способен ввести что угодно, поэтому программа не должна падать от неверного формата. Метод TryParse возвращает bool: true, если преобразование удалось, и false в противном случае. Само число передаётся через параметр out.

Console.Write("Введите целое число: ");
string? text = Console.ReadLine();

if (int.TryParse(text, out int number))
{
    Console.WriteLine($"Квадрат: {number * number}");
}
else
{
    Console.WriteLine("Это не число");
}

Чтобы требовать ввод до тех пор, пока он не станет корректным, TryParse помещают в цикл. Удобно вынести эту логику в отдельный метод и вызывать его везде, где нужен ввод числа.

static int ReadInt(string prompt, int min, int max)
{
    while (true)
    {
        Console.Write(prompt);
        if (int.TryParse(Console.ReadLine(), out int value) && value >= min && value <= max)
            return value;

        Console.WriteLine($"Нужно целое число от {min} до {max}");
    }
}

int age = ReadInt("Возраст: ", 0, 120);
Console.WriteLine($"Принято: {age}");

Для дробных значений применяют double.TryParse или decimal.TryParse. Чтобы принимать и точку, и запятую, можно заменить символ перед разбором, а чтобы не зависеть от региона, передать CultureInfo.InvariantCulture.

using System.Globalization;

string? s = Console.ReadLine()?.Replace(',', '.');
if (double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out double x))
    Console.WriteLine($"x = {x}");
else
    Console.WriteLine("Не удалось разобрать число");

Повторный запрос данных чаще всего строится на циклах, примеры есть в статье про while и do while. Если же вместо TryParse вы используете Parse, то ошибки можно перехватить через try-catch, но проверка через TryParse быстрее и проще.

Чтение клавиши: Console.ReadKey

Метод Console.ReadKey считывает одно нажатие и не требует Enter. Он возвращает структуру ConsoleKeyInfo, в которой есть свойства Key (код клавиши), KeyChar (символ) и Modifiers (Shift, Ctrl, Alt). Если передать аргумент true, нажатая клавиша не будет отображаться в консоли.

Console.WriteLine("Продолжить? (y/n)");
ConsoleKeyInfo key = Console.ReadKey(true);

if (key.Key == ConsoleKey.Y)
    Console.WriteLine("Продолжаем");
else if (key.Key == ConsoleKey.N)
    Console.WriteLine("Выход");

Console.WriteLine("Нажмите любую клавишу для завершения...");
Console.ReadKey();

ReadKey удобен для меню, игр и подтверждений. Он же часто ставится в конце учебных программ, чтобы окно не закрылось раньше времени при запуске из среды разработки. Для ввода пароля можно читать клавиши по одной и выводить звёздочки вместо символов.

Console.Write("Пароль: ");
var pass = new System.Text.StringBuilder();
ConsoleKeyInfo k;
while ((k = Console.ReadKey(true)).Key != ConsoleKey.Enter)
{
    if (k.Key == ConsoleKey.Backspace && pass.Length > 0)
    {
        pass.Length--;
        Console.Write("\b \b");
    }
    else if (!char.IsControl(k.KeyChar))
    {
        pass.Append(k.KeyChar);
        Console.Write('*');
    }
}
Console.WriteLine();
Console.WriteLine($"Длина пароля: {pass.Length}");

Цвета и оформление консоли

Свойства Console.ForegroundColor и Console.BackgroundColor задают цвет текста и фона. Значения берутся из перечисления ConsoleColor. После вывода цветного текста цвета нужно вернуть методом Console.ResetColor, иначе все последующие строки останутся окрашенными.

Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Операция выполнена");

Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Ошибка: файл не найден");

Console.BackgroundColor = ConsoleColor.DarkBlue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(" Заголовок ");
Console.ResetColor();

Console.Title = "Моя программа";
Console.Clear();
Console.SetCursorPosition(10, 3);
Console.Write("Текст в позиции (10, 3)");

Метод Console.Clear очищает окно, Console.Title меняет заголовок окна, а SetCursorPosition переносит курсор в нужную колонку и строку. Эти приёмы нужны для простых текстовых интерфейсов, индикаторов и игр. Следует учитывать, что в некоторых терминалах (например, при перенаправлении вывода в файл) изменение позиции курсора вызывает исключение IOException.

Вывод ошибок и перенаправление потоков

Кроме стандартного вывода, у консоли есть поток ошибок: Console.Error.WriteLine. Сообщения об ошибках лучше отправлять туда, чтобы при перенаправлении результата в файл они не смешивались с основными данными. Для чтения всего введённого текста, например при передаче данных через конвейер, пригодится Console.In.ReadToEnd.

Console.WriteLine("Результат: 42");
Console.Error.WriteLine("Предупреждение: данные неполные");

// чтение до конца потока ввода
string all = Console.In.ReadToEnd();
Console.WriteLine($"Получено символов: {all.Length}");

Если в консольной программе нужно прочитать несколько чисел из одной строки, введённых через пробел, разделите её методом Split и разберите каждую часть через TryParse. Приёмы разбиения описаны в статье про преобразование строки в массив.

Console.Write("Числа через пробел: ");
string[] parts = (Console.ReadLine() ?? "").Split(' ', StringSplitOptions.RemoveEmptyEntries);
int sum = 0;
foreach (string p in parts)
{
    if (int.TryParse(p, out int n))
        sum += n;
}
Console.WriteLine($"Сумма: {sum}");

Типичные ошибки

  • Использование Parse без проверки: любой неверный символ обрушивает программу.
  • Сложение введённых строк вместо чисел, из-за чего "2" + "3" даёт "23".
  • Игнорирование возможного null у ReadLine при включённых nullable-типах.
  • Потерянный разделитель дробной части: точка вместо запятой в русской региональной настройке.
  • Забытый ResetColor, после которого весь вывод остаётся цветным.
  • Закрытие окна консоли до того, как пользователь успел прочитать результат.

Частые вопросы

Чем отличаются Console.Write и Console.WriteLine?

WriteLine добавляет в конце перевод строки, поэтому следующий вывод начинается с новой строки. Write оставляет курсор сразу после текста, что подходит для подсказок вроде "Введите число: ".

Почему ReadLine возвращает строку, а не число?

Потому что с клавиатуры приходит текст, и метод не знает, что вы хотите получить. Тип нужно выбрать самостоятельно и преобразовать результат через int.Parse, int.TryParse или Convert.

Что лучше использовать: Parse или TryParse?

Для пользовательского ввода берите TryParse: он не выбрасывает исключение и позволяет вежливо попросить повторить ввод. Parse подходит там, где формат гарантирован, например при чтении собственных файлов.

Как считать число, чтобы не нажимать Enter?

Используйте Console.ReadKey для одной клавиши и переведите символ в цифру, например через char.GetNumericValue или вычитание '0'. Для многозначных чисел без Enter придётся читать клавиши по одной в цикле.

Как вывести кавычки или фигурные скобки внутри интерполяции?

Кавычки экранируют обратной косой чертой: \". Фигурные скобки удваивают: {{ и }} выведут одиночные символы. В сырых строковых литералах с тремя кавычками экранирование не нужно.

Почему русские буквы в консоли отображаются неправильно?

Причина в кодировке консоли. Установите Console.OutputEncoding = System.Text.Encoding.UTF8 и убедитесь, что используемый шрифт терминала поддерживает кириллицу. В Windows Terminal обычно проблем нет.