Пока программа ничего не спрашивает и ничего не показывает, убедиться, что она работает, невозможно. Консоль – самый прямой способ увидеть результат: два метода на вывод, один на ввод.
Вывод: WriteLine и Write
Разница между ними ровно одна – перевод строки в конце.
Console.WriteLine("Первая строка");
Console.WriteLine("Вторая строка");
Console.Write("Эти два вызова ");
Console.Write("окажутся на одной строке");
WriteLine без аргументов просто переводит каретку – так вставляют пустую строку между блоками
вывода.
Приглашение к вводу пишите через Write, а не WriteLine: тогда курсор останется на той же строке и пользователь будет печатать сразу после вопроса, а не под ним.
Подстановка значений в строку
Выводить одну лишь константу быстро надоедает. Значение переменной вставляется в строку несколькими способами, но пользоваться стоит одним.
Интерполяция строк – строка начинается с $, а выражения ставятся в фигурных скобках:
string name = "Аня";
int age = 19;
Console.WriteLine($"{name}, вам {age} лет");
Внутри скобок допустимо не только имя переменной, но и любое выражение, в том числе арифметика и вызов метода:
Console.WriteLine($"Через год будет {age + 1}");
Console.WriteLine($"Имя заглавными: {name.ToUpper()}");
Второй способ – склейка через +. Работает, но читается тяжелее, особенно когда кусков
больше двух:
Console.WriteLine(name + ", вам " + age + " лет");
Легко потерять пробел на стыке или запутаться в кавычках. В новом коде так почти не пишут.
Есть и третий вариант – string.Format с нумерованными местами вида {0}. Он старше интерполяции и до сих пор встречается в чужом коде, но самому его выбирать незачем.
Форматирование чисел
После значения через двоеточие можно указать, как его показать:
double price = 1234.5678;
Console.WriteLine($"{price:F2}"); // 1234,57 – два знака после запятой
Console.WriteLine($"{price:N0}"); // 1 235 – с разделителем групп, без дробной части
Console.WriteLine($"{0.257:P1}"); // 25,7 % – проценты
Console.WriteLine($"{DateTime.Now:dd.MM.yyyy}");
Разделителем дробной части в русской локали будет запятая, а не точка: формат зависит от настроек системы, а не от языка программирования.
Ввод: ReadLine
Метод ждёт, пока пользователь наберёт строку и нажмёт Enter, и возвращает набранное:
Console.Write("Как вас зовут? ");
string name = Console.ReadLine();
Console.WriteLine($"Здравствуйте, {name}!");
Возвращается всегда строка. Даже если пользователь ввёл одни цифры, для программы это текст: консоль не знает, что вы собирались получить число.
Console.Write("Сколько вам лет? ");
string input = Console.ReadLine();
int age = int.Parse(input); // вот теперь это число
Console.WriteLine($"Через год будет {age + 1}");
Без int.Parse строка "19" при попытке прибавить единицу дала бы не 20, а ошибку компиляции:
складывать текст с числом C# не станет.
int.Parse падает с исключением, если в строке не число: пользователь ввёл «девятнадцать» – программа аварийно завершилась. Правильный способ – int.TryParse, но у него нужна проверка результата, поэтому разберём его в уроке про преобразования типов.
Как ввод устроен в других языках
Один и тот же диалог. Разница – в том, кто отвечает за тип введённого:
Console.Write("Сколько вам лет? ");
int age = int.Parse(Console.ReadLine());
age = int(input("Сколько вам лет? "))
Обе программы делают одно и то же и обе упадут на нечисловом вводе. Но в C# тип переменной
объявлен явно, и, если убрать int.Parse, компилятор откажется собирать программу ещё до
запуска. В Python ошибка проявится только когда до неё дойдёт выполнение.
Служебные символы в строках
Некоторые символы нельзя просто напечатать внутри кавычек – их записывают через обратную косую:
| Запись | Что означает |
|---|---|
\n |
перевод строки |
\t |
табуляция |
\" |
кавычка внутри строки |
\\ |
сама обратная косая |
Из-за последнего пункта пути в Windows выглядят неуклюже: "C:\\Users\\Аня\\file.txt". Чтобы не
удваивать каждую косую, строку помечают знаком @ – тогда служебные последовательности внутри
не действуют:
string path = @"C:\Users\Аня\file.txt";
Знаки @ и $ совмещаются, и порядок с 2021 года любой: $@"..." и @$"..." работают
одинаково.
Маленькая программа целиком
Всё, что было в уроке, в одном примере:
Console.Write("Имя: ");
string name = Console.ReadLine();
Console.Write("Год рождения: ");
int year = int.Parse(Console.ReadLine());
int age = DateTime.Now.Year - year;
Console.WriteLine();
Console.WriteLine($"{name}, вам примерно {age} лет.");
Console.WriteLine($"Это {age * 12} месяцев или около {age * 365:N0} дней.");
«Примерно» здесь не из вежливости: мы знаем только год рождения, а не дату, поэтому до дня рождения ответ завышен на единицу. Программа, которая обещает точность, которой у неё нет, – худший вид ошибки: она не падает, ей просто не стоит верить.