Консольный ввод и вывод в C# — это обмен текстом между программой и терминалом через статический класс System.Console: методы Write/WriteLine пишут в стандартный поток вывода, а ReadLine, Read и ReadKey читают то, что ввел пользователь. Важно различать три вещи: чтение строки (всегда возвращает текст), разбор этого текста в число (int.TryParse) и форматирование значения обратно в текст (интерполяция, форматные строки).
Содержание
Ниже — полный рабочий пример, затем разбор вывода, ввода, типовых ошибок и того, что делать, если программа ведет себя не так. Примеры рассчитаны на .NET 10 и C# 14, но работают и на .NET 8.
Минимальная программа: спросить и ответить
Создай проект командами dotnet new console -o Hello, затем cd Hello и dotnet run. Шаблон использует инструкции верхнего уровня (top-level statements), поэтому класс Program и метод Main писать не нужно. Замени содержимое Program.cs на код ниже.
Console.Write("Как тебя зовут? ");
string? name = Console.ReadLine();
if (string.IsNullOrWhiteSpace(name))
{
name = "гость";
}
int age;
while (true)
{
Console.Write("Сколько тебе лет? ");
string? input = Console.ReadLine();
if (input is null) // ввод закрыт: Ctrl+Z и Enter в Windows, Ctrl+D в Linux/macOS
{
Console.Error.WriteLine("Ввод закрыт, выхожу.");
return;
}
if (int.TryParse(input, out age) && age is >= 0 and <= 150)
{
break;
}
Console.WriteLine("Нужно целое число от 0 до 150, попробуй еще раз.");
}
Console.WriteLine($"Привет, {name.Trim()}! Через 10 лет тебе будет {age + 10}.");
Сеанс в терминале выглядит так (после вопросительного знака — то, что ввел пользователь):
Как тебя зовут? Аня
Сколько тебе лет? двадцать
Нужно целое число от 0 до 150, попробуй еще раз.
Сколько тебе лет? 20
Привет, Аня! Через 10 лет тебе будет 30.
Что здесь происходит по строкам:
Console.Writeпечатает вопрос без перевода строки, поэтому курсор остается справа от вопроса.Console.ReadLine()ждет Enter и возвращает введенную строку без символа конца строки. Тип результата —string?: при закрытом вводе метод вернетnull, и это нужно обработать.int.TryParseпытается превратить текст в число. При неудаче он не бросает исключение, а возвращаетfalse, и цикл просит ввести значение снова.Console.Error.WriteLineпишет сообщение об ошибке в отдельный поток stderr, который не попадает в файл при перенаправлении основного вывода (> out.txt).
Вывод: Write, WriteLine и форматирование
| Метод | Что делает | Когда брать |
|---|---|---|
Console.Write(x) |
пишет значение без перевода строки | подсказка перед вводом, вывод по частям |
Console.WriteLine(x) |
пишет значение и Environment.NewLine |
обычный построчный вывод |
Console.WriteLine() |
только перевод строки | пустая строка-разделитель |
Console.Error.WriteLine(x) |
пишет в stderr | сообщения об ошибках и диагностика |
Environment.NewLine зависит от ОС: в Windows это \r\n, в Linux и macOS — \n. WriteLine подставляет его сам, поэтому вручную писать \n обычно не нужно.
Собрать строку из значений можно тремя способами, в современном коде чаще берут интерполяцию.
using System.Globalization;
string item = "Кофе";
double price = 3.5;
int qty = 12;
Console.WriteLine("Товар: " + item + ", цена: " + price); // конкатенация
Console.WriteLine("Товар: {0}, цена: {1}", item, price); // составное форматирование
Console.WriteLine($"Товар: {item}, цена: {price}"); // интерполяция
Console.WriteLine($"|{item,-8}|{qty,5}|{price,8:F2}|"); // ширина, выравнивание, формат
Console.WriteLine(price.ToString("F2", CultureInfo.InvariantCulture));
Вывод при русской культуре системы (ru-RU):
Товар: Кофе, цена: 3,5
Товар: Кофе, цена: 3,5
Товар: Кофе, цена: 3,5
|Кофе | 12| 3,50|
3.50
Разбор форматной части {значение,ширина:формат}:
{item,-8}— ширина 8 символов, минус означает выравнивание по левому краю;{qty,5}— ширина 5, выравнивание по правому краю;{price,8:F2}— ширина 8 и форматF2, то есть два знака после запятой. Другие частые форматы —N2(с разделителем групп разрядов),D4(целое с ведущими нулями),P1(процент).
Разделитель дробной части берется из текущей культуры: в ru-RU это запятая, в en-US — точка. Если вывод читает другая программа (CSV, лог, скрипт), передавай CultureInfo.InvariantCulture, как в последней строке примера.
Ввод: ReadLine, Read и ReadKey
| Метод | Возвращает | Когда ждет | Типичная задача |
|---|---|---|---|
ReadLine() |
string?, null при конце ввода |
до Enter | ввод строки или числа |
Read() |
int — код следующего символа, -1 при конце ввода |
до Enter (ввод буферизуется построчно) | посимвольный разбор потока |
ReadKey() |
ConsoleKeyInfo — клавиша, символ, модификаторы |
одно нажатие, Enter не нужен | меню, «нажми любую клавишу», игры |
Главное отличие: ReadLine и Read работают с текстом, который пришел в поток ввода, в том числе из файла через перенаправление <. ReadKey работает с клавиатурой. Если ввод перенаправлен, он бросает InvalidOperationException, поэтому перед ним стоит проверить Console.IsInputRedirected.
if (Console.IsInputRedirected)
{
Console.WriteLine("Ввод перенаправлен, интерактивное меню недоступно.");
return;
}
Console.WriteLine("Нажимай клавиши, Esc - выход.");
while (true)
{
ConsoleKeyInfo key = Console.ReadKey(intercept: true);
if (key.Key == ConsoleKey.Escape)
{
break;
}
Console.WriteLine($"Клавиша: {key.Key}, символ: '{key.KeyChar}', модификаторы: {key.Modifiers}");
}
Параметр intercept: true не дает символу появиться на экране. При нажатии Shift+A программа напечатает:
Клавиша: A, символ: 'A', модификаторы: Shift
Числа из ввода: Parse против TryParse
ReadLine всегда возвращает строку, даже если пользователь ввел цифры. Строку нужно разобрать. Частая ошибка новичка — int.Parse без проверки.
Неверно:
int n = int.Parse(Console.ReadLine());
Console.WriteLine(n * 2);
Результат: компилятор выдает предупреждение CS8604 о возможной передаче null, а при вводе abc программа падает с необработанным исключением:
Unhandled exception. System.FormatException: The input string 'abc' was not in a correct format.
Исправление — TryParse, который сообщает об успехе через bool:
Console.Write("Введи целое число: ");
if (int.TryParse(Console.ReadLine(), out int n))
{
Console.WriteLine(n * 2);
}
else
{
Console.WriteLine("Это не целое число.");
}
На ввод 21 программа выведет 42, на abc или пустую строку — «Это не целое число.». TryParse принимает и null, возвращая false. Значение, которое не помещается в int (например, 99999999999), тоже дает false, тогда как int.Parse бросил бы OverflowException.
Несколько чисел в одной строке и дробные значения
Дробные числа по умолчанию разбираются по текущей культуре: в ru-RU строка 2,5 читается, а 2.5 — нет. Если формат ввода задаешь ты сам, зафиксируй его явно.
using System.Globalization;
Console.Write("Введи два числа через пробел: ");
string line = Console.ReadLine() ?? "";
string[] parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 2
&& double.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out double a)
&& double.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out double b))
{
Console.WriteLine($"Сумма: {(a + b).ToString(CultureInfo.InvariantCulture)}");
}
else
{
Console.WriteLine("Формат: два числа через пробел, дробная часть через точку, например 2.5 4");
}
На ввод 2.5 4 программа выведет Сумма: 6.5. RemoveEmptyEntries убирает пустые элементы, поэтому лишние пробелы между числами не ломают разбор. Для денежных сумм вместо double бери decimal — он хранит десятичные дроби без двоичной погрешности в пределах своей точности.
Если не получилось
| Симптом | Причина | Что сделать |
|---|---|---|
| Окно закрывается сразу после вывода | программа завершилась, а запуск был двойным щелчком по .exe | запускать через dotnet run из терминала или добавить в конец Console.ReadKey() |
| Вместо кириллицы знаки вопроса | кодировка консоли не UTF-8 (чаще старая консоль Windows) | в начале программы Console.OutputEncoding = System.Text.Encoding.UTF8;, для ввода — Console.InputEncoding |
FormatException при вводе числа |
используется Parse без проверки или не та культура |
TryParse, для дробных — явная культура |
| Предупреждение CS8600 или CS8604 | ReadLine возвращает string? |
проверить на null или взять ?? "" |
InvalidOperationException в ReadKey |
ввод перенаправлен (файл, некоторые окна вывода IDE) | проверять Console.IsInputRedirected, для потока использовать ReadLine |
Выводы
- Вывод в консоль в C# —
Console.WriteиConsole.WriteLine, ошибки лучше писать вConsole.Error. - Интерполяция
$"{x,ширина:формат}"решает и подстановку, и выравнивание, и формат чисел; разделитель дробной части зависит от культуры. ReadLineвозвращаетstring?:nullозначает конец ввода, это не пустая строка.- Числа из ввода разбирай через
TryParse, а неParse; для машинно-читаемого формата указывайCultureInfo.InvariantCulture. ReadKeyнужен для работы с клавишами и не работает при перенаправленном вводе.
Где применяется / связь с практикой
Консольные программы — формат первых учебных задач, утилит и скриптов автоматизации. Те же TryParse, культура и обработка null потом встречаются при разборе конфигов, файлов и параметров веб-запросов.
Освойте тему на практике
Если хочешь системно пройти основы языка от консольных программ до ООП и коллекций с практикой и разбором домашних заданий, посмотри курс C# Developer. Basic. Попробовать формат обучения бесплатно можно на открытых уроках Otus.
FAQ
Как очистить консоль в C#?
Методом Console.Clear(). Если вывод перенаправлен в файл, в Windows он бросает IOException, а в Linux просто ничего не делает, поэтому в утилитах вызывай его только при !Console.IsOutputRedirected.
Как вывести текст цветом?
Задать Console.ForegroundColor = ConsoleColor.Green; перед выводом и вернуть исходные цвета через Console.ResetColor().
Как прочитать весь ввод до конца, например из файла через <?
Читать ReadLine в цикле, пока он не вернет null, или вызвать Console.In.ReadToEnd(), чтобы получить весь текст одной строкой.



