| 1 | # C# — консольные программы, уровень «8 класс» (v1) |
| 2 | |
| 3 | **doc_id:** `kb-csharp-console-grade8-v1` |
| 4 | **audience:** школьник / начинающий; цель — **понять синтаксис** и писать **простые консольные** программы без фреймворков. |
| 5 | **lang:** объяснения на русском; примеры кода — C#; запросы агента часто на русском. |
| 6 | **Не заменяет:** [`kb-dotnet-fundamentals-v1.md`](kb-dotnet-fundamentals-v1.md) (TFM, SDK, enterprise). |
| 7 | **Связь:** угадай число — lab `kb-csharp-guess-number-canonical.md` + §16 ниже. |
| 8 | |
| 9 | **Внешние опоры (для учителя/агента):** [Tour of C#](https://learn.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/overview), [Console](https://learn.microsoft.com/en-us/dotnet/api/system.console), [Random](https://learn.microsoft.com/en-us/dotnet/api/system.random). |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## 0. Педагогика курса (как учить «школьника») |
| 14 | |
| 15 | - **Куррикулярность:** сначала вывод текста, потом ввод, потом ветвления, потом циклы, потом методы и `Random`; не смешивать всё в первом уроке. |
| 16 | - **Спираль:** каждая новая тема опирается на предыдущую (например, цикл `while` в игре — после отдельного упражнения «счётчик до N»). |
| 17 | - **Рабочая память:** одна программа — один файл `Program.cs`, один `Main`; не вводить классы с полями и наследование в v1. |
| 18 | - **Формативная обратная связь:** компилятор — «учитель»: читать текст ошибки (`CS...`), исправлять **одну** ошибку за раз, снова `dotnet build`. |
| 19 | - **Эталон + вариация:** сначала разбор эталона построчно, потом задание «сделай похожее, но с другими числами/текстом». |
| 20 | - **Проверка понимания:** ученик (или агент) должен уметь **объяснить словами**, что делает каждая строка в `Main`, не только скопировать. |
| 21 | - **Ошибки — норма:** типичные ошибки (точка с запятой, типы, границы `Random.Next`) закрепляются отдельным блоком §16. |
| 22 | - **Мотивация:** программа должна что-то «делать» в консоли (диалог, игра, таблица), а не печатать абстрактные числа без смысла. |
| 23 | - **Роутер агента:** запросы «напиши консоль на C#», «объясни while», «исправь ошибку компиляции» — подтягивать этот документ; профессиональные TFM/playbook — только если явно спросили про SDK/деплой. |
| 24 | |
| 25 | *Связь с исследовательской педагогикой CASA:* слоистое обучение, редкие семантические коррекции (компилятор + разбор), среда «действие → результат» — см. `research-training-developmental-pedagogy-v1.md` (метафора, не биология). |
| 26 | |
| 27 | --- |
| 28 | |
| 29 | ## 1. Что такое программа на C# |
| 30 | |
| 31 | - **Программа** — текст на языке C#, который **компилятор** превращает в команды для компьютера. |
| 32 | - **Консольное приложение** — программа без окон: ввод и вывод идут в **терминал** (чёрное окно / встроенный терминал IDE). |
| 33 | - Файл с кодом обычно называется `Program.cs`; точка входа — метод **`static void Main()`**. |
| 34 | - Строка `using System;` подключает базовые типы (`Console`, `String`, `Int32` и др.). |
| 35 | - Команды в C# заканчиваются **точкой с запятой** `;`. |
| 36 | - Блок кода в фигурных скобках `{ }` — «тело» метода, цикла, ветки `if`. |
| 37 | - Регистр букв важен: `Console` и `console` — не одно и то же. |
| 38 | - Комментарий `//` до конца строки; многострочный `/* ... */` — для длинных пояснений. |
| 39 | - Сборка: `dotnet build`; запуск: `dotnet run` (из папки проекта с `.csproj`). |
| 40 | - **Успех урока 1:** программа печатает одну строку и завершается без ошибки сборки. |
| 41 | |
| 42 | ```csharp |
| 43 | using System; |
| 44 | class Program |
| 45 | { |
| 46 | static void Main() |
| 47 | { |
| 48 | Console.WriteLine("Hello, world!"); |
| 49 | } |
| 50 | } |
| 51 | ``` |
| 52 | |
| 53 | --- |
| 54 | |
| 55 | ## 2. Вывод в консоль: Write и WriteLine |
| 56 | |
| 57 | - `Console.WriteLine("текст");` — печатает строку и **переводит строку** (курсор на новую строку). |
| 58 | - `Console.Write("текст");` — печатает **без** перевода строки (удобно для приглашения «Введите имя: »). |
| 59 | - В кавычках — **строковый литерал**; внутри строки кавычку экранируют: `\"`. |
| 60 | - Склеивание строк: `"Привет, " + name` или интерполяция `$"Привет, {name}!"` (оба допустимы на этом уровне). |
| 61 | - Число можно вывести: `Console.WriteLine(42);` или `Console.WriteLine(sum);`. |
| 62 | - Пустая строка: `Console.WriteLine();` — просто перевод строки. |
| 63 | - **Типичная ошибка:** забыть `;` после `WriteLine` → ошибка компилятора около строки. |
| 64 | |
| 65 | --- |
| 66 | |
| 67 | ## 3. Переменные и типы (int, string, bool) |
| 68 | |
| 69 | - **Переменная** — именованная «ячейка» в памяти: `int age = 14;` |
| 70 | - **`int`** — целое число (−2 147 483 648 … 2 147 483 647). |
| 71 | - **`string`** — текст; литерал в двойных кавычках: `string name = "Аня";` |
| 72 | - **`bool`** — логическое: `true` или `false`. |
| 73 | - Объявление с типом: `int x = 10;` Ключевое слово **`var`** — компилятор выводит тип: `var n = 5;` → `int`. |
| 74 | - Присваивание меняет значение: `x = x + 1;` или кратко `x++;` (увеличить на 1). |
| 75 | - Имена переменных — `camelCase` (первая буква строчная): `userName`, `totalSum`. |
| 76 | - Нельзя использовать зарезервированные слова как имена: `int`, `class`, `string`. |
| 77 | - **Сравнение чисел:** `==`, `!=`, `<`, `>`, `<=`, `>=` — результат типа `bool`. |
| 78 | - **Логика:** `&&` (и), `||` (или), `!` (не). |
| 79 | |
| 80 | --- |
| 81 | |
| 82 | ## 4. Ввод с клавиатуры: ReadLine и TryParse |
| 83 | |
| 84 | - `string line = Console.ReadLine();` — читает строку до Enter (может быть `null` в редких случаях; на учебном уровне проверять пустую строку). |
| 85 | - Текст **не является числом** автоматически: `"42"` — string, не int. |
| 86 | - Безопасное преобразование: `int.TryParse(line, out int value)` → `true`, если удалось; иначе `false`. |
| 87 | - Паттерн ввода числа: |
| 88 | |
| 89 | ```csharp |
| 90 | Console.Write("Введите число: "); |
| 91 | var line = Console.ReadLine(); |
| 92 | if (!int.TryParse(line, out int n)) |
| 93 | { |
| 94 | Console.WriteLine("Это не число."); |
| 95 | return; // или continue в цикле |
| 96 | } |
| 97 | ``` |
| 98 | |
| 99 | - Для **двух чисел** — два раза `ReadLine` + два `TryParse`, или один разделитель (позже). |
| 100 | - **Педагогика:** сначала научить выводить подсказку `Write`, потом читать `ReadLine`. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ## 5. Ветвление: if, else if, else |
| 105 | |
| 106 | - `if (условие) { ... }` — выполнить блок, только если условие **истинно**. |
| 107 | - `else { ... }` — иначе (взаимоисключающая ветка). |
| 108 | - `else if (другое_условие) { ... }` — цепочка проверок (как «иначе если»). |
| 109 | - Фигурные скобки обязательны для ясности на учебном уровне, даже для одной строки. |
| 110 | - Вложенные `if` допустимы, но лучше не углубляться больше 2–3 уровней — вынести в метод (§10). |
| 111 | - **Тернарный оператор** (опционально): `int max = (a > b) ? a : b;` |
| 112 | - Сравнение строк: `name == "Аня"` или `string.Equals(a, b)`; для учебника часто достаточно `==`. |
| 113 | |
| 114 | --- |
| 115 | |
| 116 | ## 6. Цикл while |
| 117 | |
| 118 | - `while (условие) { тело }` — повторять, пока условие **true**. |
| 119 | - Бесконечный цикл: `while (true)` + выход через `break` при нужном событии. |
| 120 | - `break` — немедленно выйти из цикла; `continue` — перейти к следующей итерации. |
| 121 | - Перед циклом инициализировать счётчик/флаг; внутри — менять переменные, иначе зацикливание. |
| 122 | - **Счётчик:** `int i = 0; while (i < 10) { ...; i++; }` |
| 123 | |
| 124 | --- |
| 125 | |
| 126 | ## 7. Цикл for |
| 127 | |
| 128 | - `for (инициализация; условие; шаг) { тело }` — когда **известно число повторений**. |
| 129 | - Классика: `for (int i = 1; i <= 10; i++)` — `i` от 1 до 10 включительно. |
| 130 | - Переменная `i` в заголовке `for` видна только внутри цикла (область видимости). |
| 131 | - Таблица умножения одной строки: цикл по множителю 1..10. |
| 132 | - `for` и `while` взаимозаменяемы; `for` удобнее для счётчиков, `while` — «пока не угадал». |
| 133 | |
| 134 | --- |
| 135 | |
| 136 | ## 8. switch и простое меню |
| 137 | |
| 138 | - `switch (переменная)` — выбор по **дискретным** значениям (часто `int` или `string`). |
| 139 | - Каждая ветка: `case 1:` … `break;` Иначе — `default:`. |
| 140 | - **Меню:** напечатать варианты, `ReadLine`/`TryParse` выбор, `switch` по номеру, `break` из внешнего `while` для выхода (например, пункт 0). |
| 141 | - Забытый `break` после `case` → ошибка компилятора (намеренно строго). |
| 142 | |
| 143 | ```csharp |
| 144 | switch (choice) |
| 145 | { |
| 146 | case 1: |
| 147 | Console.WriteLine("Пункт 1"); |
| 148 | break; |
| 149 | case 2: |
| 150 | Console.WriteLine("Пункт 2"); |
| 151 | break; |
| 152 | default: |
| 153 | Console.WriteLine("Неизвестный пункт"); |
| 154 | break; |
| 155 | } |
| 156 | ``` |
| 157 | |
| 158 | --- |
| 159 | |
| 160 | ## 9. Случайные числа: System.Random |
| 161 | |
| 162 | - `var rnd = new Random();` — генератор псевдослучайных чисел. |
| 163 | - `rnd.Next(1, 101)` — целое **от 1 включительно до 100 включительно** (верхняя граница **исключается**). |
| 164 | - Диапазон 1..100: всегда писать `Next(1, 101)`, не `Next(100)`. |
| 165 | - `rnd.Next(0, 2)` — 0 или 1 (монетка). |
| 166 | - Один объект `Random` на программу — достаточно для учебных задач. |
| 167 | - **Игра «угадай число»:** одно `secret`, цикл `while`, сравнение `guess` с `secret`, подсказки «больше»/«меньше». |
| 168 | |
| 169 | --- |
| 170 | |
| 171 | ## 10. Методы static (подпрограммы) |
| 172 | |
| 173 | - **Метод** — именованный блок кода: `static int Add(int a, int b) { return a + b; }` |
| 174 | - `static` — вызывать из `Main` без создания объекта класса (достаточно для 8 класса). |
| 175 | - `void` — метод ничего не возвращает; `int`, `string` и др. — тип возвращаемого значения + `return значение;` |
| 176 | - Вызов: `int s = Add(2, 3);` |
| 177 | - Параметры — копии значений для `int`/`bool`; для учебника не углубляться в `ref`/`out` кроме `TryParse`. |
| 178 | - Вынос повторяющегося кода в метод улучшает читаемость (например, `PrintMenu()`). |
| 179 | |
| 180 | --- |
| 181 | |
| 182 | ## 11. Массив и среднее (минимум для оценок) |
| 183 | |
| 184 | - Массив фиксированной длины: `int[] grades = { 5, 4, 5 };` или `int[] g = new int[3];` |
| 185 | - Длина: `grades.Length`; элемент: `grades[i]` (индекс с **0**). |
| 186 | - Сумма в цикле: `int sum = 0; for (int i = 0; i < grades.Length; i++) sum += grades[i];` |
| 187 | - Среднее: `double avg = (double)sum / grades.Length;` — приведение типа, иначе целочисленное деление. |
| 188 | - Альтернатива без массива на первом проходе: три переменные `g1,g2,g3` — допустимо для K0, массив — шаг вперёд. |
| 189 | |
| 190 | --- |
| 191 | |
| 192 | ## 12. Эталон 1: Hello, имя |
| 193 | |
| 194 | **Задача:** спросить имя, поздороваться. |
| 195 | **Навыки:** `Write`, `ReadLine`, конкатенация или `$"..."`. |
| 196 | |
| 197 | ```csharp |
| 198 | using System; |
| 199 | class Program |
| 200 | { |
| 201 | static void Main() |
| 202 | { |
| 203 | Console.Write("Your name: "); |
| 204 | var name = Console.ReadLine(); |
| 205 | Console.WriteLine("Hello, " + name + "!"); |
| 206 | } |
| 207 | } |
| 208 | ``` |
| 209 | |
| 210 | - Gold (lab): `examples/exp_k_grade8/gold/01_hello_name.cs` |
| 211 | - Вариация для ученика: изменить приветствие на русский; добавить проверку пустого имени. |
| 212 | |
| 213 | --- |
| 214 | |
| 215 | ## 13. Эталон 2: Сумма двух чисел |
| 216 | |
| 217 | **Задача:** ввести два целых, вывести сумму. |
| 218 | **Навыки:** два `TryParse`, арифметика `+`. |
| 219 | |
| 220 | ```csharp |
| 221 | using System; |
| 222 | class Program |
| 223 | { |
| 224 | static void Main() |
| 225 | { |
| 226 | Console.Write("First number: "); |
| 227 | if (!int.TryParse(Console.ReadLine(), out int a)) { Console.WriteLine("Not a number."); return; } |
| 228 | Console.Write("Second number: "); |
| 229 | if (!int.TryParse(Console.ReadLine(), out int b)) { Console.WriteLine("Not a number."); return; } |
| 230 | Console.WriteLine("Sum = " + (a + b)); |
| 231 | } |
| 232 | } |
| 233 | ``` |
| 234 | |
| 235 | - Gold: `examples/exp_k_grade8/gold/02_sum_two.cs` |
| 236 | |
| 237 | --- |
| 238 | |
| 239 | ## 14. Эталон 3: Таблица умножения (одно число, 1..10) |
| 240 | |
| 241 | **Задача:** напечатать строки `7 x 1 = 7` … `7 x 10 = 70`. |
| 242 | **Навыки:** `for`, умножение. |
| 243 | |
| 244 | ```csharp |
| 245 | using System; |
| 246 | class Program |
| 247 | { |
| 248 | static void Main() |
| 249 | { |
| 250 | int n = 7; |
| 251 | for (int i = 1; i <= 10; i++) |
| 252 | Console.WriteLine(n + " x " + i + " = " + (n * i)); |
| 253 | } |
| 254 | } |
| 255 | ``` |
| 256 | |
| 257 | - Gold: `examples/exp_k_grade8/gold/03_multiply_table.cs` |
| 258 | - Вариация: `n` ввести с клавиатуры после `TryParse`. |
| 259 | |
| 260 | --- |
| 261 | |
| 262 | ## 15. Эталон 4: Максимум из трёх чисел |
| 263 | |
| 264 | **Задача:** ввести три числа, вывести наибольшее. |
| 265 | **Навыки:** цепочка `if / else if`, или вложенные сравнения. |
| 266 | |
| 267 | ```csharp |
| 268 | using System; |
| 269 | class Program |
| 270 | { |
| 271 | static void Main() |
| 272 | { |
| 273 | Console.Write("a: "); |
| 274 | int.TryParse(Console.ReadLine(), out int a); |
| 275 | Console.Write("b: "); |
| 276 | int.TryParse(Console.ReadLine(), out int b); |
| 277 | Console.Write("c: "); |
| 278 | int.TryParse(Console.ReadLine(), out int c); |
| 279 | int max = a; |
| 280 | if (b > max) max = b; |
| 281 | if (c > max) max = c; |
| 282 | Console.WriteLine("Max = " + max); |
| 283 | } |
| 284 | } |
| 285 | ``` |
| 286 | |
| 287 | - Gold: `examples/exp_k_grade8/gold/04_max_of_three.cs` |
| 288 | |
| 289 | --- |
| 290 | |
| 291 | ## 16. Эталон 5: Угадай число (1..100) |
| 292 | |
| 293 | **Правила:** загадать `secret`, игрок вводит `guess`, ответ **Higher** / **Lower** / **Correct**, цикл до победы. |
| 294 | |
| 295 | - `int secret = rnd.Next(1, 101);` |
| 296 | - `while (true)` + `break` при угадывании. |
| 297 | - `if (guess < secret)` → «больше» (число загадано выше вводимого). |
| 298 | - `if (!int.TryParse(...))` → «Enter a number» и `continue`. |
| 299 | |
| 300 | ```csharp |
| 301 | using System; |
| 302 | class Program |
| 303 | { |
| 304 | static void Main() |
| 305 | { |
| 306 | var rnd = new Random(); |
| 307 | int secret = rnd.Next(1, 101); |
| 308 | while (true) |
| 309 | { |
| 310 | Console.Write("Guess (1-100): "); |
| 311 | if (!int.TryParse(Console.ReadLine(), out int guess)) |
| 312 | { Console.WriteLine("Enter a number."); continue; } |
| 313 | if (guess < secret) Console.WriteLine("Higher"); |
| 314 | else if (guess > secret) Console.WriteLine("Lower"); |
| 315 | else { Console.WriteLine("Correct!"); break; } |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | ``` |
| 320 | |
| 321 | - Gold: `examples/exp_k_guess_number/gold/Program.cs` (тот же эталон в Exp K). |
| 322 | |
| 323 | --- |
| 324 | |
| 325 | ## 17. Эталон 6: Меню с циклом |
| 326 | |
| 327 | **Задача:** показывать меню 1/2/0 (выход), повторять до выхода. |
| 328 | **Навыки:** `while`, `switch`, `TryParse` для выбора. |
| 329 | |
| 330 | ```csharp |
| 331 | using System; |
| 332 | class Program |
| 333 | { |
| 334 | static void Main() |
| 335 | { |
| 336 | while (true) |
| 337 | { |
| 338 | Console.WriteLine("1 - Say hi"); |
| 339 | Console.WriteLine("2 - Show date"); |
| 340 | Console.WriteLine("0 - Exit"); |
| 341 | Console.Write("Choice: "); |
| 342 | if (!int.TryParse(Console.ReadLine(), out int choice)) continue; |
| 343 | switch (choice) |
| 344 | { |
| 345 | case 1: Console.WriteLine("Hi!"); break; |
| 346 | case 2: Console.WriteLine(DateTime.Now); break; |
| 347 | case 0: return; |
| 348 | default: Console.WriteLine("Unknown"); break; |
| 349 | } |
| 350 | } |
| 351 | } |
| 352 | } |
| 353 | ``` |
| 354 | |
| 355 | - Нужен `using System;` для `DateTime` — допустимое расширение после базового курса. |
| 356 | - Gold: `examples/exp_k_grade8/gold/06_menu.cs` |
| 357 | |
| 358 | --- |
| 359 | |
| 360 | ## 18. Эталон 7: Счётчик от 1 до N |
| 361 | |
| 362 | **Задача:** ввести `N`, напечатать числа 1, 2, …, N. |
| 363 | **Навыки:** `for`, ввод. |
| 364 | |
| 365 | ```csharp |
| 366 | using System; |
| 367 | class Program |
| 368 | { |
| 369 | static void Main() |
| 370 | { |
| 371 | Console.Write("N: "); |
| 372 | if (!int.TryParse(Console.ReadLine(), out int n) || n < 1) { Console.WriteLine("Bad N"); return; } |
| 373 | for (int i = 1; i <= n; i++) |
| 374 | Console.WriteLine(i); |
| 375 | } |
| 376 | } |
| 377 | ``` |
| 378 | |
| 379 | - Gold: `examples/exp_k_grade8/gold/07_counter_to_n.cs` |
| 380 | |
| 381 | --- |
| 382 | |
| 383 | ## 19. Эталон 8: Среднее оценок |
| 384 | |
| 385 | **Задача:** ввести количество оценок, затем оценки, вывести среднее. |
| 386 | **Навыки:** массив или цикл накопления суммы. |
| 387 | |
| 388 | ```csharp |
| 389 | using System; |
| 390 | class Program |
| 391 | { |
| 392 | static void Main() |
| 393 | { |
| 394 | Console.Write("How many grades: "); |
| 395 | if (!int.TryParse(Console.ReadLine(), out int count) || count < 1) return; |
| 396 | int sum = 0; |
| 397 | for (int i = 0; i < count; i++) |
| 398 | { |
| 399 | Console.Write("Grade: "); |
| 400 | int.TryParse(Console.ReadLine(), out int g); |
| 401 | sum += g; |
| 402 | } |
| 403 | double avg = (double)sum / count; |
| 404 | Console.WriteLine("Average = " + avg); |
| 405 | } |
| 406 | } |
| 407 | ``` |
| 408 | |
| 409 | - Gold: `examples/exp_k_grade8/gold/08_average_grades.cs` |
| 410 | |
| 411 | --- |
| 412 | |
| 413 | ## 20. Типичные ошибки компиляции (учить читать сообщение) |
| 414 | |
| 415 | | Симптом / CS | Частая причина | Что сделать | |
| 416 | |--------------|----------------|-------------| |
| 417 | | `; expected` | Нет `;` в конце оператора | Добавить `;` | |
| 418 | | `The name 'X' does not exist` | Опечатка, нет `using`, переменная вне области | Проверить имя и `{}` | |
| 419 | | `Cannot implicitly convert type` | Присвоили string в int | `TryParse` или `Convert` | |
| 420 | | `Use of unassigned local variable` | Читали переменную до присвоения | Инициализировать или ветка `if` | |
| 421 | | `No overload for 'Next' takes 1 arguments` | Путаница `Next(max)` vs `Next(min,max)` | Для 1..100: `Next(1, 101)` | |
| 422 | | Бесконечный вывод | `while` без изменения условия | Менять счётчик или `break` | |
| 423 | | `break` вне цикла | `break` не в `while`/`for`/`switch` | Перенести внутрь цикла | |
| 424 | |
| 425 | - **Педагогика:** не менять десять строк сразу — исправить **первую** ошибку в списке компилятора, пересобрать. |
| 426 | - Агент при emit: после `dotnet build` подставлять digest из §20 + фрагмент кода вокруг строки из сообщения. |
| 427 | |
| 428 | --- |
| 429 | |
| 430 | ## 21. Чеклист «понял ли ученик» (для агента / преподавателя) |
| 431 | |
| 432 | - Может написать Hello + ввод имени без копирования эталона целиком. |
| 433 | - Объясняет разницу `Write` и `WriteLine`. |
| 434 | - Вводит число через `TryParse`, а не `int.Parse` без обработки (на учебном уровне — знать риск исключения). |
| 435 | - Пишет `if/else` для сравнения трёх чисел. |
| 436 | - Пишет `for` для таблицы и `while` для игры. |
| 437 | - Знает границы `Random.Next(min, maxExclusive)`. |
| 438 | - Собирает проект командой `dotnet build` и интерпретирует одну ошибку CS. |
| 439 | - **K4 (Exp K):** не менее **6 из 8** эталонных задач (§12–19) — build OK по gold-логике. |
| 440 | |
| 441 | --- |
| 442 | |
| 443 | ## 22. Операционное использование в CASA / Exp K |
| 444 | |
| 445 | - Store: `code-agent-lab-v0`; bundle stem `kb-csharp-console-grade8-v1`. |
| 446 | - Recall (K0): запросы про `Console`, `TryParse`, `while`, `Random`, «напиши сумму двух чисел». |
| 447 | - Emit (K2+): digest из top claims + эталон ближайшей задачи; не смешивать с `kb-dotnet-fundamentals-v1` без запроса. |
| 448 | - Профессиональный стиль кода — [`code-writing-principles-v1.md`](../software-authoring/code-writing-principles-v1.md) — **после** того как программа компилируется. |
| 449 | |
| 450 | **Версия:** v1 · 2026-05-29 |
| 451 | |
| 452 | |