Основы C# с нуля

Курс знакомит с языком C# и базовыми принципами программирования для начинающих. Вы изучите синтаксис, типы данных, управляющие конструкции, ООП и работу с коллекциями, а также сделаете первые консольные приложения.

1. Введение в C# и настройка среды разработки

Введение в C# и настройка среды разработки

Зачем нужен C# и где он применяется

C# (читается как си шарп) — современный язык программирования, который чаще всего используют вместе с платформой .NET.

C# подходит для:

  • Консольных и серверных приложений
  • Веб-разработки (ASP.NET Core)
  • Десктопных приложений (Windows, кроссплатформенно)
  • Игр (Unity)
  • Микросервисов и облачных сервисов
  • Официальная документация по C#: Документация по C#

    Что такое .NET и чем SDK отличается от Runtime

    Чтобы писать и запускать программы на C#, нужен .NET.

    Ключевые понятия:

  • .NET Runtime — набор компонентов, необходимых только для запуска уже готовых приложений.
  • .NET SDK — всё, что нужно для разработки: компилятор C#, инструменты командной строки, шаблоны проектов.
  • Для обучения и написания кода вам нужен именно .NET SDK.

    Скачать .NET: Загрузка .NET

    Что такое IDE и чем она помогает

    IDE — среда разработки, которая ускоряет работу программиста.

    Обычно IDE умеет:

  • Подсвечивать ошибки и подсказывать код
  • Запускать и отлаживать приложение
  • Управлять файлами проекта
  • Подключать библиотеки
  • Ниже — популярные варианты для C#.

    | Инструмент | Для кого подходит | Особенности | |---|---|---| | Visual Studio | Новички и профессионалы | Самая полная IDE для C# на Windows, мощный отладчик | | Visual Studio Code | Тем, кто любит лёгкие редакторы | Нужны расширения, зато быстро и кроссплатформенно | | JetBrains Rider | Тем, кто хочет мощь на всех ОС | Платный, но очень удобный и умный |

    Ссылки:

  • Visual Studio
  • Visual Studio Code
  • JetBrains Rider
  • Установка .NET SDK

    Windows

  • Откройте страницу: Загрузка .NET
  • Выберите актуальную версию .NET SDK (обычно предлагают LTS)
  • Скачайте установщик и установите SDK
  • Перезапустите терминал (если он был открыт)
  • macOS

  • Откройте: Загрузка .NET
  • Скачайте .NET SDK для macOS
  • Установите пакет
  • Перезапустите терминал
  • Linux

  • Откройте: Загрузка .NET
  • Выберите вашу дистрибуцию и следуйте официальной инструкции
  • Установите .NET SDK через пакетный менеджер
  • Проверка установки

    Откройте терминал (PowerShell/Windows Terminal на Windows, Terminal на macOS/Linux) и выполните команду:

    Если SDK установлен, вы увидите номер версии (например, 8.0.xxx).

    Полезная справка по инструментам: dotnet CLI

    Установка редактора и настройка для C#

    Вариант A: Visual Studio (Windows)

  • Установите Visual Studio: Visual Studio
  • Во время установки выберите рабочую нагрузку .NET desktop development (для консольных проектов тоже подходит)
  • После установки создавайте проект через меню создания проекта
  • Вариант B: Visual Studio Code (Windows/macOS/Linux)

  • Установите VS Code: Visual Studio Code
  • Установите расширение C#:
  • - C# (ms-dotnettools.csharp)
  • Убедитесь, что .NET SDK установлен (проверка через dotnet --version)
  • Вариант C: Rider (Windows/macOS/Linux)

  • Установите Rider: JetBrains Rider
  • Rider обычно сам подхватывает установленный .NET SDK
  • Создаём первый проект на C# через командную строку

    Даже если вы используете IDE, важно уметь делать базовые действия через dotnet CLI — это универсально.

    Создание проекта

  • Создайте папку для проектов (любую)
  • В терминале перейдите в неё
  • Выполните команду:
  • Команда создаст папку HelloCSharp с готовым консольным проектом.

    Документация по шаблонам: dotnet new

    Запуск проекта

    Перейдите в папку проекта:

    Запустите приложение:

    Документация: dotnet run

    !Схема показывает, что вы пишете код, затем проект собирается и запускается с помощью .NET SDK

    Что находится внутри проекта

    После создания проекта вы увидите несколько файлов. Самые важные для старта:

  • Program.cs — исходный код программы
  • HelloCSharp.csproj — файл проекта (в нём указаны настройки сборки и зависимости)
  • Пример кода

    Внутри Program.cs вы увидите простую программу. В современных версиях C# часто используются верхнеуровневые операторы, поэтому код может выглядеть очень коротко:

    Что здесь происходит:

  • Console — класс для работы с консолью
  • WriteLine — вывод строки и перевод на новую строку
  • строка в кавычках — текст, который будет напечатан
  • Сборка и запуск: в чём разница

    В .NET обычно разделяют два действия:

  • Сборка — компиляция проекта в исполняемые файлы
  • Запуск — выполнение результата сборки
  • Команды:

  • dotnet build — только сборка
  • dotnet run — сборка (если нужно) и запуск
  • Частые проблемы и как их решить

  • dotnet: command not found или «не является внутренней или внешней командой»
  • - Проверьте, что установлен именно .NET SDK, и перезапустите терминал
  • Установлен Runtime, но нет SDK
  • - Скачайте SDK на странице: Загрузка .NET
  • VS Code не видит C# или не работает подсветка
  • - Убедитесь, что установлено расширение: C# (ms-dotnettools.csharp) - Проверьте dotnet --version

    Что будет дальше в курсе

    В следующих материалах мы будем постепенно разбирать:

  • Типы данных и переменные
  • Операторы и выражения
  • Условия и циклы
  • Методы и работа с параметрами
  • Основы объектов и классов
  • На этом этапе ваша цель — чтобы среда разработки была настроена, и вы уверенно создавали и запускали консольные проекты на C#.

    2. Типы данных, переменные и базовые операции

    Типы данных, переменные и базовые операции

    После того как вы установили .NET SDK, создали консольный проект и научились запускать его через dotnet run, следующий шаг — понять, из чего состоят данные в программе и как с ними работать. В C# это начинается с типов данных, переменных и базовых операций.

    Что такое тип данных

    Тип данных отвечает на два ключевых вопроса:

  • Сколько памяти нужно, чтобы хранить значение
  • Какие операции можно выполнять (например, складывать, сравнивать, проверять на null)
  • В C# у каждого значения есть тип. Даже у строки "Привет" и числа 42.

    Переменные

    Переменная — это именованное место (точнее, ссылка на место) для хранения значения определённого типа.

    Общий вид объявления:

    Где:

  • int, string, bool — тип
  • age, name, isStudent — имя переменной
  • = — присваивание
  • справа — значение
  • Правила именования

  • Имя может содержать буквы, цифры и _, но не может начинаться с цифры
  • В C# регистр важен: age и Age — разные имена
  • Обычно используют стиль camelCase для локальных переменных: userName, totalPrice
  • Встроенные типы C#

    В C# есть набор встроенных (примитивных) типов, которые используются постоянно.

    Числовые типы

    | Тип | Что хранит | Пример | |---|---|---| | int | целые числа (чаще всего используется) | int a = 10; | | long | большие целые числа | long b = 10_000_000_000; | | double | числа с дробной частью (плавающая точка) | double x = 3.14; | | decimal | дробные числа для денег и точных расчётов | decimal p = 19.99m; |

    Обратите внимание:

  • В long литералах часто нужен суффикс L, но обычно компилятор и так понимает по значению
  • У decimal литералов принято ставить m: 10.5m
  • В числах можно использовать _ для удобства чтения: 1_000_000
  • Документация: Встроенные типы (C#)

    Логический, символьный и строковый типы

    | Тип | Что хранит | Пример | |---|---|---| | bool | true или false | bool ok = true; | | char | один символ в одинарных кавычках | char c = 'A'; | | string | строку (текст) в двойных кавычках | string s = "Hello"; |

    Важно:

  • char — это один символ, а stringнабор символов
  • string можно склеивать и форматировать
  • Значимые и ссылочные типы

    В C# типы делятся на две большие категории:

  • значимые типы (например, int, bool, double, decimal, char)
  • ссылочные типы (например, string, массивы, классы)
  • Упрощённая идея:

  • Значимый тип хранит само значение
  • Ссылочный тип хранит ссылку на объект в памяти
  • !Сравнение хранения значимых и ссылочных типов

    Практический вывод для новичка:

  • При присваивании значимых типов чаще всего копируется значение
  • При присваивании ссылочных типов копируется ссылка на один и тот же объект
  • Неявно типизированные переменные var

    Иногда удобнее, чтобы компилятор сам вывел тип по правой части:

    Важно:

  • var — это не “любой тип”. Это конкретный тип, просто записанный короче
  • Переменную с var нужно обязательно инициализировать сразу
  • После вывода типа он уже не меняется
  • Документация: Неявно типизированные локальные переменные (var)

    Константы const

    Константа — значение, которое нельзя изменить после объявления.

    Ограничение:

  • const должно быть вычисляемо во время компиляции (то есть нельзя сделать const из результата Console.ReadLine())
  • null и nullable-типы

    null означает “нет значения” (чаще всего — “нет объекта”).

    Для ссылочных типов это привычно:

    Но значимые типы (например, int) по умолчанию не могут быть null. Если нужно “число или ничего”, используют nullable-типы:

    int? читается как nullable int и означает “int или null”.

    Часто применяют проверку:

    Базовые операции

    Арифметические операции

    Для чисел доступны стандартные операции:

  • + сложение
  • - вычитание
  • * умножение
  • / деление
  • % остаток от деления
  • Пример:

    Ключевой момент: если делите int на int, результат тоже int (дробная часть отбрасывается). Чтобы получить дробный результат, хотя бы одно число должно быть дробным:

    Операторы сравнения

    Результат сравнения — всегда bool.

  • == равно
  • != не равно
  • > больше
  • < меньше
  • >= больше или равно
  • <= меньше или равно
  • Пример:

    Логические операции

    Работают с bool:

  • && логическое И (true, если обе части true)
  • || логическое ИЛИ (true, если хотя бы одна часть true)
  • ! логическое НЕ
  • Пример:

    Присваивание и сокращённые операции

    Кроме =, есть сокращения:

  • += прибавить и присвоить
  • -= вычесть и присвоить
  • *= умножить и присвоить
  • /= разделить и присвоить
  • Пример:

    Инкремент и декремент

  • ++ увеличить на 1
  • -- уменьшить на 1
  • Пример:

    Строки: конкатенация и интерполяция

    Склеивание строк

    Можно склеивать строки через +:

    Интерполяция строк

    Чаще удобнее использовать интерполяцию — строку с "Name: {name}, age: {age}"); csharp double x = 9.8; int y = (int)x; Console.WriteLine(y); // 9 csharp Console.Write("Введите число: "); string? input = Console.ReadLine();

    if (int.TryParse(input, out int number)) { Console.WriteLine($"Вы ввели {number}"); } else { Console.WriteLine("Это не целое число"); } csharp checked { int max = int.MaxValue; int overflowed = max + 1; // вызовет исключение в checked-контексте Console.WriteLine(overflowed); } `

    В повседневных задачах новичка это встречается редко, но важно знать, что у чисел есть предел.

    Документация: checked и unchecked (C#)

    Итог

    Теперь вы умеете:

  • объявлять переменные и выбирать подходящий тип (int, double, decimal, bool, char, string)
  • понимать разницу между значимыми и ссылочными типами на базовом уровне
  • использовать var, const и int? (nullable)
  • применять базовые операции: арифметика, сравнение, логика, присваивание
  • преобразовывать значения: приведение типов и TryParse` для ввода
  • В следующем материале эти знания станут основой для условий и циклов, где переменные и операции используются постоянно.

    3. Условия, циклы и управление потоком программы

    Условия, циклы и управление потоком программы

    После типов данных, переменных и операций следующий важный шаг — научиться управлять тем, какие строки кода выполняются и сколько раз они повторяются. Именно это и называется управление потоком программы.

    Что такое управление потоком

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

  • выполнять одни действия только если выполнено условие
  • повторять действия, пока выполняется условие
  • выбирать один вариант из нескольких
  • прерывать выполнение цикла или метода
  • Для этого в C# используются:

  • условные конструкции if, else, switch
  • циклы while, do-while, for, foreach
  • управляющие операторы break, continue, return
  • !Схема показывает, как программа ветвится по условию и повторяет действия в цикле

    Условие if, ветки else и else if

    if выполняет блок кода, если условие истинно (true). Условие в if обязательно должно иметь тип bool.

    Пример:

    Что важно понимать:

  • выражение в скобках (...) должно быть логическим, например age >= 18
  • фигурные скобки { ... } задают блок кода
  • else выполняется, когда условие в if ложно (false)
  • Цепочка else if

    Когда вариантов больше двух, используют else if.

    Проверки идут сверху вниз: как только находится первая подходящая ветка, остальные уже не проверяются.

    Блоки и область видимости переменных

    Переменная, объявленная внутри блока { ... }, существует только внутри этого блока.

    switch: выбор одного варианта из нескольких

    switch удобен, когда нужно сравнить одно значение с несколькими вариантами.

    Пример со строкой:

    Здесь:

  • case — конкретный вариант
  • default — что делать, если ни один case не подошёл
  • break — завершает выполнение switch (чтобы не “провалиться” дальше)
  • Документация: Оператор switch (C#)

    switch-выражение: когда нужно получить значение

    Иногда нужно не просто выполнить код, а получить результат.

    Символ _ означает “всё остальное”.

    Документация: Выражение switch (C#)

    Тернарный оператор ?:

    Если нужно выбрать одно из двух значений по условию, можно использовать тернарный оператор.

    Читать это можно так: если age >= 18, то одна строка, иначе другая.

    Циклы: повторение действий

    Циклы нужны, когда одно и то же действие надо повторять много раз.

    Сравнение циклов

    | Цикл | Когда использовать | Особенность | |---|---|---| | while | повторять, пока условие истинно | проверка условия до тела цикла | | do-while | нужно выполнить тело хотя бы один раз | проверка условия после тела | | for | известно количество повторений или есть счётчик | удобно задавать счётчик | | foreach | пройти по элементам набора (массив, список) | не нужен индекс вручную |

    Цикл while

    while повторяет блок кода, пока условие true.

    Пример: читаем числа, пока не введут 0, и суммируем их.

    Документация: foreach (C#)

    Управляющие операторы break, continue, return

    break

    break немедленно завершает ближайший цикл или switch.

  • в цикле это означает “выйти из повторения”
  • в switch это означает “закончить обработку выбранного case”
  • continue

    continue пропускает оставшуюся часть тела цикла и переходит к следующей итерации.

    Пример: вывести только нечётные числа.

    return

    return завершает выполнение метода. В простых консольных примерах это часто означает “закончить программу здесь”.

    Частые ошибки новичков

  • Путаница = и ==
  • - = присваивает значение - == сравнивает
  • Бесконечный цикл
  • - условие цикла всегда true и нет break или изменения данных
  • Слишком сложные условия в if
  • - лучше разбивать на понятные шаги и использовать промежуточные переменные

    Итог

    Теперь вы умеете:

  • ветвить выполнение программы через if, else if, else
  • выбирать вариант через switch и получать результат через switch-выражение
  • повторять действия циклами while, do-while, for, foreach
  • управлять выполнением с помощью break, continue, return
  • Дальше эти конструкции станут основой для более крупных тем: методов, массивов, коллекций и написания программ, которые решают реальные задачи.

    4. Методы, параметры и основы модульности

    Методы, параметры и основы модульности

    Когда вы уже умеете работать с типами данных, переменными, условиями и циклами, следующий шаг — научиться организовывать код. В реальных программах быстро появляется повторение: ввод чисел, проверки, вычисления, вывод результатов. Если держать всё в одном длинном Program.cs, код становится трудно читать и сложно изменять.

    Методы решают эту проблему: они позволяют разбивать программу на небольшие понятные части и переиспользовать их.

    Что такое метод и зачем он нужен

    Метод — это именованный блок кода, который можно вызвать (запустить) из разных мест программы.

    Методы помогают:

  • уменьшать дублирование кода
  • делать программу более читаемой
  • изолировать детали реализации (вызову метода не обязательно знать, как именно он работает внутри)
  • проще находить и исправлять ошибки
  • Это основа модульности: программа строится как набор небольших модулей (методов), каждый из которых делает свою задачу.

    !Схема помогает увидеть, как программа разбивается на методы и как данные передаются между ними

    Документация: Методы (C#)

    Анатомия метода: что в нём написано

    В классическом виде метод в C# выглядит так:

    Разберём части:

  • тип результата: int означает, что метод возвращает целое число
  • имя: Sum — по нему мы вызываем метод
  • параметры: (int a, int b) — входные данные для метода
  • тело метода: код в { ... }
  • return — завершает метод и отдаёт результат вызывающему коду
  • Если метод ничего не возвращает, используют void:

    Связь с прошлыми темами:

  • используется цикл while
  • используется проверка через int.TryParse
  • используется return, чтобы выйти из метода и вернуть результат
  • Параметры: как передавать данные в метод

    Параметры — это входные значения метода. Самый частый вариант — передача по значению.

    Передача по значению

    Если параметр обычный (без ref и out), то метод получает копию значения (для значимых типов, например int). Изменения параметра внутри метода не меняют исходную переменную.

    ref: передача с возможностью изменить исходную переменную

    ref означает, что метод работает с той же переменной, а не с копией. Изменения внутри метода будут видны снаружи.

    Требование:

  • переменная должна быть инициализирована до передачи в ref
  • Документация: ref, out и in (C#)

    out: вернуть результат через параметр

    out полезен, когда метод должен вернуть дополнительное значение, либо когда по смыслу результат логично вернуть через параметр.

    Пример: упрощённо повторим идею TryParse.

    Что вы получаете:

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

  • Путаница между параметром и аргументом
  • Попытка использовать переменную, объявленную внутри метода, снаружи
  • Ожидание, что обычный параметр изменит исходную переменную (когда нужен ref)
  • Слишком большие методы
  • Хорошее правило для старта: если метод тяжело назвать одной короткой фразой, возможно, он делает слишком много.

    Итог

    Теперь вы умеете:

  • создавать и вызывать методы
  • передавать данные через параметры
  • возвращать результат через return и понимать void
  • использовать ref и out на базовом уровне
  • применять перегрузку, необязательные и именованные параметры
  • разбивать консольные задачи на небольшие методы и писать более модульный код
  • Дальше эти навыки станут основой для более сложных тем: массивов и коллекций (где методы часто обрабатывают наборы данных), а также классов и объектов (где методы становятся поведением объектов).

    5. Массивы, строки и коллекции

    Массивы, строки и коллекции

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

    В C# для этого чаще всего используют:

  • массивы T[] — фиксированный размер
  • строки string — текст (тоже набор символов)
  • коллекции из стандартной библиотеки, например List<T> и Dictionary<TKey, TValue> — размер может меняться
  • Массивы

    Массив — это набор элементов одного типа, к которым можно обращаться по индексу.

  • Индекс — это номер элемента
  • Индексация начинается с 0
  • Размер массива задаётся при создании и дальше не меняется
  • !Массив как ряд ячеек: индексы начинаются с 0

    Создание массива

    #### Вариант с перечислением элементов

    #### Вариант с указанием размера

    Полезное свойство:

  • Length — количество элементов
  • Документация: Массивы (C#)

    Доступ к элементам и ошибки индексов

    Чтение и запись элемента:

    Важно:

  • допустимые индексы: от 0 до numbers.Length - 1
  • обращение вне диапазона приводит к ошибке выполнения IndexOutOfRangeException
  • Перебор массива: for и foreach

    for удобен, когда нужен индекс:

    csharp string name = "Ivan";

    string a = "Hello, " + name; string b = "Введено чисел: {numbers.Count}"); csharp using System.Collections.Generic;

    Dictionary<string, int> stock = new Dictionary<string, int>();

    stock["apple"] = 10; // добавить или перезаписать stock["banana"] = 5;

    Console.WriteLine(stock["apple"]); // 10 csharp if (stock.TryGetValue("pear", out int count)) { Console.WriteLine($"Груш: {count}"); } else { Console.WriteLine("Груш нет в словаре"); } ``

    Документация: Класс Dictionary<TKey,TValue>

    Когда выбирать массив, List<T> или Dictionary<TKey, TValue>

    | Инструмент | Когда подходит | Как обращаться | |---|---|---| | T[] | размер известен и не меняется | по индексу array[i] | | List<T> | размер меняется, нужен порядок элементов | по индексу list[i] | | Dictionary<TKey, TValue> | нужен быстрый доступ по ключу | по ключу dict[key] или TryGetValue |

    Частые ошибки новичков

  • Путаница в индексации
  • Использование Length вместо Count и наоборот
  • Ожидание, что строка “изменится сама” после +=
  • Обращение к Dictionary по несуществующему ключу без TryGetValue
  • Итог

    Теперь вы знаете основу работы с наборами данных:

  • массивы T[]: индексы, Length, перебор
  • строки string: Length, доступ к символам, Split, неизменяемость
  • коллекции List<T> и Dictionary<TKey, TValue>`: добавление, чтение, безопасный доступ
  • Дальше эти знания помогут писать более практичные программы: обработку списков, поиск, подсчёты, хранение данных по ключам — и подготовят вас к следующему крупному шагу: объектам и классам, где коллекции часто становятся полями объектов, а методы — операциями над этими данными.

    6. Основы ООП: классы, объекты, наследование

    Основы ООП: классы, объекты, наследование

    Когда вы пишете программы на C#, вы уже используете идеи объектно-ориентированного программирования, даже если не замечаете этого. Например, Console и List<int> — это классы, у которых есть методы и данные.

    В прошлых темах вы научились работать с условиями, циклами, методами и коллекциями. Теперь следующий шаг — понять, как упаковывать данные и поведение вместе, чтобы код был проще, безопаснее и расширяемее. Это и есть основная идея ООП.

    Что такое ООП простыми словами

    Объектно-ориентированное программирование — это подход, в котором программа состоит из объектов.

  • Объект хранит данные (состояние) и умеет выполнять действия (поведение)
  • Класс описывает, какие данные и действия будут у объектов
  • Можно думать так:

  • Класс — это чертёж
  • Объект — это конкретный экземпляр, сделанный по чертежу
  • !Иллюстрация различия между классом и объектами

    Класс и объект в C#

    Создаём свой класс

    Класс обычно объявляют в отдельном файле, но для обучения можно написать всё в одном проекте.

    Пример класса Person:

    Здесь:

  • public class Person — объявление класса
  • Name и Age — данные человека (состояние)
  • HaveBirthday() — действие (поведение)
  • Документация: Классы (C#)

    Создаём объект и вызываем методы

    Ключевые моменты:

  • new Person(...) создаёт объект
  • p.Name и p.Age читают данные объекта
  • p.HaveBirthday() изменяет состояние объекта
  • Поля и свойства

    Когда класс хранит данные, у вас есть два основных инструмента: поля и свойства.

    Поле

    Поле обычно делают private, чтобы защитить внутреннее состояние.

    Свойство

    Свойство — это удобный и безопасный способ дать доступ к данным.

    Что важно:

  • Balance { get; private set; } означает:
  • - читать можно всем (get публичный) - изменять можно только внутри класса (set приватный)
  • так класс защищает свои данные от случайной порчи снаружи
  • Документация: Свойства (C#)

    Инкапсуляция: почему данные лучше прятать

    Инкапсуляция — это принцип ООП: объект сам отвечает за корректность своих данных.

    Практический смысл для новичка:

  • не давайте внешнему коду напрямую менять важные значения
  • делайте методы, которые меняют состояние безопасно (с проверками)
  • Например, если сделать Balance полностью публичным (get и set), то кто угодно сможет написать account.Balance = -1, и состояние станет некорректным.

    Конструктор

    Конструктор — это специальный метод, который вызывается при создании объекта через new. Его задача — подготовить объект к работе.

    Пример:

    Здесь конструктор гарантирует, что прямоугольник не будет создан с неправильными размерами.

    Документация: Конструкторы (C#)

    Ключевое слово this

    this — это ссылка на текущий объект внутри его метода или конструктора.

    Чаще всего this нужно, когда имя параметра совпадает с именем поля.

    На практике чаще выбирают стиль, где поля называются с подчёркиванием (_name), чтобы реже писать this.

    Модификаторы доступа: public и private

    Модификатор доступа определяет, кто может видеть класс, метод или данные.

    | Модификатор | Что означает | |---|---| | public | доступно отовсюду | | private | доступно только внутри этого класса | | protected | доступно внутри класса и у наследников | | internal | доступно внутри текущего проекта |

    Документация: Модификаторы доступа (C#)

    Наследование: переиспользование и расширение

    Наследование позволяет создать новый класс на основе существующего.

  • Базовый класс хранит общую логику
  • Производный класс расширяет или уточняет поведение
  • Пример: есть общий тип Animal и конкретные животные Cat и Dog.

    Как это использовать:

    Здесь:

  • Cat : Animal означает, что Cat наследуется от Animal
  • base(name) вызывает конструктор базового класса
  • Документация: Наследование (C#)

    !Схема показывает идею базового класса и классов-наследников

    Полиморфизм: один интерфейс, разное поведение

    Полиморфизм в C# часто проявляется так:

  • переменная базового типа может хранить объект производного типа
  • при вызове виртуального метода сработает версия производного класса
  • Чтобы это работало, используют virtual и override.

    virtual и override

    Частые ошибки новичков в ООП

  • Смешивание ответственности
  • Слишком публичные поля и свойства
  • Ожидание, что наследование решит любую задачу
  • Забытый virtual у метода базового класса при попытке использовать override
  • Практическое правило на старте:

  • если класс хранит важные данные, делайте изменение данных через методы, а не прямым set
  • Итог

    Теперь вы знаете базовые элементы ООП в C#:

  • класс как описание и объект как экземпляр
  • поля и свойства, базовую инкапсуляцию
  • конструкторы и инициализацию объекта
  • наследование (: и base(...))
  • базовый полиморфизм через virtual и override
  • идею абстрактных классов
  • Следующий естественный шаг после этого материала — углубиться в проектирование классов, познакомиться с интерфейсами и научиться строить небольшие программы, где логика распределена по нескольким классам, а Program.cs содержит только сценарий запуска.

    7. Исключения, ввод-вывод и мини-проект консольного приложения

    Исключения, ввод-вывод и мини-проект консольного приложения

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

    В этой статье вы научитесь:

  • понимать, что такое исключения и зачем они нужны
  • правильно обрабатывать ошибки через try/catch/finally
  • делать ввод-вывод: консоль и файлы
  • собрать мини-проект консольного приложения с сохранением данных в файл
  • Что такое исключения

    Исключение (exception) — это сигнал о том, что во время выполнения программы произошла ошибка, и нормальный ход выполнения нарушен.

    Примеры причин:

  • деление на ноль
  • попытка обратиться к несуществующему индексу массива
  • чтение файла, которого нет
  • некорректный формат данных
  • Если исключение не обработать, программа обычно завершается с сообщением об ошибке.

    Документация: Исключения и обработка исключений

    !Схема показывает, как управление переходит из try в catch при ошибке и что finally выполняется всегда

    try, catch, finally

    Базовая конструкция обработки исключений:

  • try содержит потенциально опасный код
  • catch ловит исключение и позволяет программе продолжить работу
  • finally выполняется всегда (и при успехе, и при ошибке), обычно для освобождения ресурсов
  • Документация: try-catch-finally

    Пример: безопасное чтение числа

    Вы уже использовали int.TryParse (и это правильный способ для ввода). Но иногда ошибки возникают не на вводе, а глубже.

    Здесь важно:

  • int.Parse бросает исключение, если строка некорректна
  • TryParse исключение не бросает, а возвращает false
  • Когда использовать TryParse, а когда try/catch

  • Для ожидаемых ошибок ввода (пользователь ввёл не то) чаще используйте TryParse
  • Для ошибок внешней среды (файл, сеть, права доступа) часто нужны try/catch
  • Практическое правило для старта:

  • если ситуация нормальная и ожидаемая — лучше без исключений (Try...-подход)
  • если ситуация редкая и не норма — используйте исключения
  • throw: как создавать свои ошибки

    Иногда вы хотите явно запретить некорректное состояние и остановить текущую операцию.

  • throw создаёт и выбрасывает исключение
  • ArgumentException подходит, когда аргумент метода некорректен
  • nameof(b) даёт имя параметра как строку
  • Документация: throw

    Основные типы исключений, которые вы будете встречать

    | Исключение | Когда возникает | Пример ситуации | |---|---|---| | FormatException | неверный формат данных | int.Parse("abc") | | ArgumentException | неверный аргумент метода | отрицательная длина, пустое имя | | IndexOutOfRangeException | неверный индекс массива | arr[100] при Length = 3 | | FileNotFoundException | файл не найден | чтение отсутствующего файла | | UnauthorizedAccessException | нет прав доступа | запись в защищённую папку |

    Ввод-вывод: консоль

    С консолью вы уже работали:

  • Console.WriteLine выводит текст и перевод строки
  • Console.Write выводит без перевода строки
  • Console.ReadLine читает строку
  • Полезные практики для ввода:

  • Trim() убирает пробелы по краям
  • проверяйте null, потому что Console.ReadLine() возвращает string?
  • Ввод-вывод: файлы

    Файлы — это типичный источник исключений, поэтому почти всегда работа с ними идёт в связке с try/catch.

    В .NET есть удобный класс File для простых сценариев.

    Документация: Класс File

    Запись текста в файл

    Чтение текста из файла

    Документация: File.Exists

    Обработка ошибок при работе с файлами

    Что здесь используется:

  • инкапсуляция: IsDone нельзя менять напрямую снаружи
  • защита от некорректных данных через throw
  • Хранилище: TaskRepository

    Создайте файл TaskRepository.cs:

    Заметьте связь с прошлыми темами:

  • коллекции: List<TaskItem>
  • методы: маленькие методы Add, Done, Remove
  • ООП: TaskItem как объект с поведением MarkDone
  • Точка входа: Program.cs

    В Program.cs (консольный проект) разместите основной цикл команд:

    Здесь важны две идеи:

  • ошибки команд не должны “ронять” приложение, поэтому вокруг обработки команды стоит try/catch
  • сохранение выполняется в конце, и его ошибки тоже обрабатываются
  • Частые ошибки новичков при работе с исключениями и I/O

  • Ловить Exception и молча игнорировать
  • Использовать исключения там, где есть TryParse и проверки
  • Не продумывать, что делать, если файл повреждён или не существует
  • Смешивать в одном месте ввод, логику и сохранение, вместо разделения на методы и классы
  • Итог

    Теперь у вас есть практическая база для написания устойчивых консольных программ:

  • вы понимаете, что такое исключения и как работает try/catch/finally
  • умеете осознанно выбирать между Try...-подходом и исключениями
  • умеете читать и писать файлы через File.* и обрабатывать ошибки I/O
  • собрали мини-проект, где используются методы, коллекции и классы
  • С этого момента вы готовы писать консольные приложения, которые не “ломаются” от первого же неверного ввода или проблемы с файлом, и постепенно усложнять архитектуру: добавлять больше классов, команд и форматов хранения данных.