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

Содержание
Вывод текста: 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 обычно проблем нет.





