Uchyoba

Home

❯

Учёба

❯

Теория

❯

2.1.2026

❯

Языки программирования

❯

Экзамен

Экзамен

24 июн. 2026 г.время чтения ~20 мин.

1. Полиморфизм. Инкапсуляция. Наследование.

Три фундаментальных принципа объектно-ориентированного программирования (ООП), на которых строится архитектура приложений в C#.

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

  • Реализация в C#: Осуществляется с помощью модификаторов доступа (private, protected, internal, public). Состояние класса обычно хранится в private полях, а доступ к ним предоставляется через public методы или свойства (properties) с аксессорами get и set.
  • Смысл: Защита данных от некорректного изменения извне (например, проверка возраста на отрицательное значение в set-аксессоре) и скрытие сложности реализации.

2. Наследование Механизм, позволяющий создать новый класс (производный/наследник) на основе существующего (базового/родительского). Наследник перенимает все поля, свойства и методы родителя (кроме приватных конструкторов), может их использовать, изменять или добавлять новые.

  • Реализация в C#: Обозначается двоеточием: class Derived : Base. В C# поддерживается только множественное наследование интерфейсов, но множественное наследование реализаций (классов) запрещено (один класс может иметь только одного прямого предка). Вызов родительского конструктора или метода осуществляется через ключевое слово base.
  • Смысл: Исключение дублирования кода (DRY) и выстраивание иерархии “is-a” (является).

3. Полиморфизм Способность системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта. Буквально — “множество форм”. Позволяет одному и тому же коду работать с разными типами данных.

  • Статический полиморфизм (во время компиляции): Перегрузка методов (methods overloading) — создание методов с одинаковым именем, но разной сигнатурой (разным набором параметров).
  • Динамический полиморфизм (во время выполнения): Переопределение методов (method overriding). В C# родительский класс объявляет метод как virtual (или abstract), а класс-наследник переопределяет его логику с помощью ключевого слова override. При вызове такого метода через ссылку базового типа среда CLR (Common Language Runtime) автоматически определяет фактический тип объекта в памяти и вызывает соответствующую переопределенную реализацию.

2. Классы и объекты в С#

Класс (Class) Класс в C# — это пользовательский ссылочный тип данных (reference type), представляющий собой чертеж, шаблон или метаданные. Он описывает структуру: какие данные (поля, константы) и какое поведение (методы, свойства, события, конструкторы) будут иметь сущности, созданные по этому шаблону.

  • Классы в C# не занимают память под данные программы до момента их инстанцирования.
  • Классы поддерживают наследование и интерфейсы.

Объект (Object / Instance) Объект — это конкретный экземпляр класса. Если класс — это чертеж дома, то объект — это сам построенный дом.

  • Память: Так как класс является ссылочным типом, объекты всегда создаются в управляемой куче (Managed Heap). Переменная, в которую сохраняется объект, хранится в стеке (Stack) и содержит лишь ссылку (адрес в памяти) на фактические данные в куче.
  • Создание: Инстанцирование объекта происходит с помощью оператора new, который выделяет память в куче, обнуляет её, вызывает конструктор класса для инициализации состояния и возвращает ссылку на объект: MyClass obj = new MyClass();.
  • Жизненный цикл: Разработчик управляет только созданием объектов. Уничтожение объектов и освобождение памяти в C# происходит автоматически с помощью сборщика мусора (Garbage Collector — GC), когда на объект больше не остается активных ссылок.

3. Обработка параметров командной строки в C#

Параметры командной строки — это строковые аргументы, которые передаются программе операционной системой в момент её запуска через консоль/терминал (например, myapp.exe -v output.txt).

В C# существует два основных способа работы с этими параметрами:

1. Через параметр метода Main Классическая точка входа в программу на C# принимает массив строк: static void Main(string[] args)

  • Массив args содержит все переданные аргументы.
  • Важное отличие от C/C++: В C# нулевой элемент args[0] — это первый переданный аргумент, а не имя исполняемого файла.
  • Аргументы разделяются пробелами. Если нужно передать строку с пробелами как один аргумент, её заключают в двойные кавычки: myapp.exe "file with spaces.txt".

2. Через класс Environment В любом месте программы (даже глубоко в других классах, вне метода Main) можно получить доступ к аргументам запуска с помощью метода: string[] args = Environment.GetCommandLineArgs();

  • Ключевое отличие: В массиве, возвращаемом этим методом, индекс [0] всегда содержит путь к исполняемому файлу (или имя сборки), а пользовательские аргументы начинаются с индекса [1].

Современный C# (Top-level statements): Начиная с C# 9, при использовании неявной точки входа (top-level statements) массив args доступен “из коробки” прямо в корне файла Program.cs без явного объявления метода Main.

4. Разделение интересов (Separation of Concerns, SoC)

Разделение интересов (SoC) — это фундаментальный принцип программной инженерии, направленный на разделение компьютерной программы на независимые секции (модули, слои, классы), каждая из которых отвечает за отдельную, специфическую задачу (интерес).

Суть принципа в C#:

  • Бизнес-логика (расчеты, правила предметной области) не должна смешиваться с логикой работы с базой данных (SQL-запросы, Entity Framework) или с логикой отображения (UI, кнопки, HTTP-ответы).
  • Это достигается за счет создания разных пространств имен (namespaces), изолированных сборок (Class Library projects) и применения интерфейсов (interfaces) для абстрагирования слоев друг от друга.

Реализация на практике:

  1. Паттерны архитектуры: MVC (Model-View-Controller), MVP, MVVM. В MVC:
    • Model — отвечает только за данные и бизнес-логику.
    • View — отвечает только за отображение.
    • Controller — отвечает за маршрутизацию и связывание.
  2. Связь с SOLID: Принцип SoC тесно связан с буквой S из SOLID — Single Responsibility Principle (Принцип единственной ответственности). Класс должен иметь только одну причину для изменения.

Преимущества: Высокая тестируемость (можно написать Unit-тесты для логики, не поднимая базу данных), легкость поддержки, возможность параллельной работы команд (одни делают UI, другие — ядро), низкая связность (loose coupling).

5. Ввод и вывод информации. Форматирование строк

Ввод/Вывод в консоли: В C# консольный I/O осуществляется через статический класс System.Console.

  • Вывод:
    • Console.Write() — выводит текст без перехода на новую строку.
    • Console.WriteLine() — выводит текст и добавляет символ переноса строки (\r\n в Windows).
  • Ввод:
    • Console.ReadLine() — читает строку, введенную пользователем, до нажатия Enter. Возвращает тип string (или string?).
    • Console.ReadKey() — считывает одно нажатие клавиши (возвращает структуру ConsoleKeyInfo).
    • Console.Read() — считывает следующий символ из стандартного потока ввода и возвращает его ASCII/Unicode код (тип int).

Форматирование строк: C# предлагает три основных способа интеграции переменных в текст и их форматирования:

  1. Композитное форматирование (String.Format): Использует индексы в фигурных скобках. Console.WriteLine("Имя: {0}, Возраст: {1}", name, age); string res = string.Format("Цена: {0:C}", price);

  2. Строковая интерполяция (String Interpolation) (начиная с C# 6.0): Перед строкой ставится символ $. Самый современный и читаемый подход. Выражения пишутся прямо внутри фигурных скобок. Console.WriteLine($"Имя: {name}, Возраст: {age}");

  3. Спецификаторы формата: Используются после двоеточия для указания типа вывода. Работают как в string.Format, так и в интерполяции.

    • (Currency) — форматирует число как валюту (в зависимости от локали ОС, например $10.00 или 10,00 ₽).
    • {:F2} (Fixed-point) — число с фиксированным количеством знаков после запятой (например, 3.14).
    • {:D5} (Decimal) — целое число с добивкой нулями слева (например, 00042).
    • (Hexadecimal) — шестнадцатеричный формат.
    • — пользовательское форматирование даты.

6. Методы

Метод — это именованный блок кода, содержащий последовательность инструкций для выполнения определенной задачи. В C# все методы должны быть частью класса или структуры (в C# нет глобальных функций, как в C++).

Структура объявления метода: [модификатор_доступа] [модификатор] <возвращаемый_тип> <ИмяМетода>([параметры]) { // тело }

  • Модификаторы: public, private, static (метод принадлежит классу, а не объекту), virtual, async и др.
  • Возвращаемый тип: Любой тип данных C# или void, если метод ничего не возвращает. Для void оператор return можно опустить или использовать просто return; для выхода из метода.

Передача параметров в методы:

  1. По значению (по умолчанию): В метод копируется значение переменной (для значимых типов) или копия ссылки (для ссылочных). Изменение самого параметра внутри метода не затрагивает исходную переменную.
  2. По ссылке (ref): В метод передается физический адрес переменной. Требует обязательной инициализации переменной до её передачи в метод. Любые изменения внутри метода отражаются на исходной переменной.
  3. Выходной параметр (out): Как и ref, передает по ссылке, но переменная может быть не инициализирована до вызова. Метод обязан присвоить значение параметру out до выхода. Используется для возврата нескольких значений (например, int.TryParse).
  4. Входной параметр (in): Передача по ссылке, но с запретом на изменение внутри метода (read-only reference). Используется для оптимизации производительности при передаче больших структур (struct).

Дополнительные возможности:

  • Необязательные параметры: Позволяют задать дефолтное значение (void Do(int x = 5)). Должны идти в конце списка параметров.
  • Именованные аргументы: При вызове метода аргументы можно передавать не по порядку, а указывая имя параметра: Do(age: 25, name: "Ivan").
  • Expression-bodied методы: Сокращенный синтаксис (через =>) для методов из одной строки: public int Add(int a, int b) => a + b;.
  • Параметр params: Позволяет передавать в метод переменное количество аргументов, которые внутри упаковываются в массив (void Log(params string[] msgs)).

7. Циклы: for, foreach/in

В C# циклы используются для многократного выполнения блока кода.

1. Цикл for Классический цикл со счетчиком. Выполняется до тех пор, пока истинно заданное условие. Синтаксис:

for (инициализация; условие; итерация) 
{ 
    // тело цикла 
}
  • Инициализация: выполняется один раз перед стартом (например, int i = 0).
  • Условие: проверяется перед каждой итерацией. Если true — цикл выполняется, если false — прерывается (например, i < 10).
  • Итерация: выполняется после каждого прохода тела цикла (например, i++).
  • Особенности: Все три блока в заголовке for опциональны (можно написать for(;;), получив бесконечный цикл). В for можно объявлять сразу несколько переменных (for (int i=0, j=10; i < j; i++, j--)).

2. Цикл foreach / in Цикл, специально разработанный для перебора элементов массивов и любых коллекций (списков, словарей и т.д.). Синтаксис:

foreach (Тип элемент in коллекция) 
{ 
    // действия с элементом 
}
  • Принцип работы (под капотом): Компилятор разворачивает foreach в конструкцию while, которая использует интерфейсы IEnumerable и IEnumerator. Сначала вызывается метод GetEnumerator(), а затем в цикле проверяется MoveNext() и извлекается свойство Current.
  • Ограничения (Важно!):
    1. Итерационная переменная (элемент) доступна только для чтения (read-only). Нельзя изменить сам элемент коллекции, написав элемент = новое_значение; (для структур и примитивов).
    2. Нельзя изменять структуру самой коллекции (добавлять или удалять элементы) внутри цикла foreach. Если попытаться это сделать (например, list.Remove(item)), будет выброшено исключение InvalidOperationException (коллекция была изменена).

8. Циклы: while, do/while

Циклы while и do/while используются для выполнения блока кода до тех пор, пока заданное логическое условие остается истинным. Они оптимальны в ситуациях, когда точное количество итераций заранее неизвестно и зависит от динамических данных (например, ввод пользователя, чтение из файла до конца).

1. Цикл while (цикл с предусловием) Проверяет условие до выполнения тела цикла. Если условие ложно изначально, тело цикла не выполнится ни одного раза. Синтаксис:

while (условие) 
{ 
    // тело цикла
}

2. Цикл do/while (цикл с постусловием) Проверяет условие после выполнения тела цикла. Главная особенность: тело цикла гарантированно выполнится хотя бы один раз, независимо от истинности условия. Синтаксис:

do 
{ 
    // тело цикла
} while (условие); // Обязательна точка с запятой в конце!

9. Условие if…else. Конструкция switch.

Это основные конструкции ветвления в C#, управляющие потоком выполнения программы.

1. Конструкция if...else Позволяет выполнить блок кода в зависимости от истинности логического (булева) выражения. Выражение обязательно должно возвращать тип bool (в отличие от C++, где можно передать int и 0 расценивается как false). Синтаксис:

if (условие1) {
    // выполнится, если условие1 == true
} else if (условие2) {
    // выполнится, если условие1 == false, а условие2 == true
} else {
    // выполнится, если все предыдущие условия ложны
}

2. Конструкция switch Механизм множественного выбора, сравнивающий значение выражения (паттерн) с набором констант (меток case). Ключевые особенности switch в C#:

  • В отличие от C/C++, в C# запрещено “проваливание” (fall-through) между непустыми блоками case. Каждый блок с кодом обязан завершаться оператором безусловного перехода: break, return, goto или throw.
  • Проваливание допускается, только если блок case полностью пуст (полезно для группировки условий).
  • С версии C# 7.0 конструкция поддерживает сопоставление с образцом (Pattern Matching), что позволяет проверять не только точное совпадение значений, но и типы данных (например, case int i when i > 0:).
  • С версии C# 8.0 доступны выражения switch (switch expressions), которые позволяют писать более компактный код, сразу возвращающий значение (например, var res = x switch { 1 => "Один", _ => "Другое" };).

10. Поразрядный оператор И

Поразрядное (битовое) И (AND) обозначается символом &. Выполняет логическую операцию И над каждой соответствующей парой битов двух целочисленных операндов.

Таблица истинности: Результат равен 1 только в том случае, если оба соответствующих бита операндов равны 1. В остальных случаях (1&0, 0&1, 0&0) результат равен 0.

Практическое применение в программировании: Применяется для маскирования битов (извлечения или проверки состояния конкретного бита). Пример: Чтобы проверить, установлен ли третий бит в числе, мы применяем маску: if ((number & 4) == 4). (Примечание: оператор & в C# также может применяться к типам bool. В отличие от логического &&, он не выполняет сокращенное (short-circuit) вычисление, а гарантированно вычисляет оба операнда).

11. Поразрядный оператор ИЛИ

Поразрядное (битовое) ИЛИ (OR) обозначается символом |. Выполняет логическую операцию ИЛИ над каждой парой битов.

Таблица истинности: Результат равен 0 только в том случае, если оба бита равны 0. Если хотя бы один из битов равен 1, результат будет 1.

Практическое применение в программировании: Применяется для установки (включения) битов или комбинирования флагов (битовых масок). Пример: Использование перечислений с атрибутом [Flags]. var options = Option.Read | Option.Write; устанавливает в переменной одновременно и бит чтения, и бит записи.

12. Поразрядный оператор исключающее ИЛИ

Поразрядное исключающее ИЛИ (XOR) обозначается символом ^.

Таблица истинности: Результат равен 1, если соответствующие биты операндов различны (1^0 = 1, 0^1 = 1). Результат равен 0, если биты одинаковы (1^1 = 0, 0^0 = 0).

Практическое применение в программировании:

  1. Инвертирование (переключение) конкретных битов: x ^ mask переключит те биты в числе x, где в маске стоят единицы.
  2. Свойство обратимости (a ^ b ^ b = a) используется в простейшем криптографическом шифровании и вычислении контрольных сумм.
  3. Обнуление регистра: a ^ a всегда равно 0.
  4. Обмен значениями двух целочисленных переменных без использования временной памяти (Swap): a ^= b; b ^= a; a ^= b;.

13. Поразрядный оператор НЕ

Поразрядное (битовое) НЕ (NOT) обозначается символом ~ (тильда). В отличие от предыдущих, это унарный оператор (применяется к одному числу).

Таблица истинности: Инвертирует каждый бит числа: заменяет все нули на единицы, а все единицы на нули (побитовое дополнение).

Практическое применение в программировании:

  1. В математике дополнительных кодов инверсия тесно связана со сменой знака числа: -x = ~x + 1.
  2. Создание обратных масок для сброса (выключения) битов. Пример: Чтобы сбросить (установить в 0) третий бит числа (маска 4, бинарно 00000100), не затронув остальные, используют конструкцию x = x & ~4;. Тильда инвертирует маску в 11111011, а оператор & “пропускает” все биты, кроме третьего, который обнуляется.

14. Простые массивы

Определение: Простой (одномерный) массив — это структура данных, хранящая фиксированное количество элементов одного типа в непрерывном блоке памяти. В C# массивы являются ссылочными типами (Reference Types) и неявно наследуются от базового абстрактного класса System.Array.

Особенности:

  • Индексация: Начинается с 0. Индекс последнего элемента равен Length - 1. Обращение к несуществующему индексу вызывает исключение времени выполнения IndexOutOfRangeException.
  • Память: Поскольку массив — ссылочный тип, переменная-массив (в стеке) хранит лишь ссылку на область памяти в куче (Managed Heap), где физически располагаются сами элементы.
  • Создание: Размер массива задается при инстанцировании оператором new и в дальнейшем изменить его нельзя (в отличие от List<T>).
int[] numbers = new int[5]; // массив из 5 целых чисел (инициализируются нулями)
string[] names = { "Alice", "Bob" }; // синтаксический сахар для инициализации
  • Современный C#: Доступны индексы от конца (numbers[^1] — последний элемент) и диапазоны (ranges, numbers[1..3]).

15. Прямоугольный массив

Определение: Прямоугольный массив в C# — это истинно многомерный массив, элементы которого организованы в виде матрицы (решетки). Характерная черта: каждая строка (измерение) имеет строго одинаковую длину.

Синтаксис и особенности:

  • Объявление: Измерения разделяются запятой внутри одних квадратных скобок [,].
int[,] matrix = new int[3, 4]; // Матрица 3 строки на 4 столбца
  • Инициализация:
int[,] matrix2 = { {1, 2}, {3, 4}, {5, 6} };
  • Доступ к элементам: Осуществляется через одну пару скобок с указанием индексов через запятую: matrix[0, 1] = 5;.
  • Метаданные: Свойство Length возвращает общее количество элементов (в примере выше — 12). Чтобы узнать длину конкретного измерения, используется метод GetLength(int dimension). Например, matrix.GetLength(0) вернет 3 (число строк), а matrix.GetLength(1) вернет 4 (число столбцов).
  • В памяти: Физически все элементы прямоугольного массива располагаются в куче как единый непрерывный блок памяти. Вычисление адреса нужного элемента происходит математически через смещение, что делает обращение к элементам очень быстрым.

16. Ломаный массив (Зубчатый массив)

Определение: Ломаный (или зубчатый) массив в C# (Jagged Array) — это массив массивов. В отличие от прямоугольного массива, где каждая строка имеет одинаковую длину, в ломаном массиве каждая строка (внутренний массив) является самостоятельным объектом и может иметь совершенно разную длину.

Синтаксис и особенности:

  • Объявление: Используются двойные квадратные скобки [][].
    int[][] jagged = new int[3][]; // Массив из 3-х ссылок на другие массивы
  • Инициализация: В отличие от прямоугольного массива, ломаный массив нельзя инициализировать одним действием (если не использовать явный синтаксис инициализации элементов). Необходимо выделить память под каждый внутренний массив отдельно:
    jagged[0] = new int[5]; // Первая строка: 5 элементов
    jagged[1] = new int[2]; // Вторая строка: 2 элемента
    jagged[2] = new int[8]; // Третья строка: 8 элементов
  • Доступ к элементам: Осуществляется через двойные скобки: jagged[0][1] = 42;. Первая скобка обращается к внешнему массиву и возвращает ссылку на внутренний массив, вторая — обращается к элементу этого внутреннего массива.
  • Организация в памяти: Ломаный массив не является единым непрерывным блоком памяти. В куче создается один “главный” массив, который хранит только ссылки на другие массивы. Сами внутренние массивы разбросаны по куче (Managed Heap) независимо друг от друга. Это снижает производительность из-за двойного разыменования указателей (pointer chasing) и нагрузки на сборщик мусора (GC), но позволяет существенно экономить память, если данные сильно разрежены.

17. Перечисление в C# (enum)

Определение: Перечисление (enum) — это значимый тип данных (Value Type), который определяет набор строго типизированных именованных целочисленных констант. Все перечисления в C# неявно наследуются от базового класса System.Enum.

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

Особенности и синтаксис:

  • Базовый тип: По умолчанию базовым типом для элементов перечисления является int, а отсчет начинается с 0.
    enum Days { Mon, Tue, Wed } // Mon = 0, Tue = 1, Wed = 2
  • Явное указание типа и значений: Можно изменить базовый тип (на byte, short, long) и задать произвольные значения:
    enum ErrorCode : short { None = 0, NotFound = 404, ServerError = 500 }
  • Преобразование типов (Casting): Так как enum основан на числах, его можно явно приводить к числу и обратно: int val = (int)Days.Mon;.
  • Битовые флаги ([Flags]): Если применить к перечислению атрибут [Flags] и задать константам значения степеней двойки (1, 2, 4, 8…), то значения enum можно будет комбинировать с помощью поразрядного ИЛИ (|) и проверять с помощью поразрядного И (&) (или встроенного метода .HasFlag()). Это позволяет хранить множество состояний в одной переменной.

18. Структуры (struct)

Определение: Структура (struct) в C# — это пользовательский значимый тип данных (Value Type), предназначенный для создания легковесных объектов, объединяющих логически связанные данные.

Ключевые отличия структур от классов (class):

  1. Хранение в памяти: Поскольку структура является Value Type, экземпляры структур выделяются в стеке (Stack), если они объявлены как локальные переменные, либо встраиваются (inlined) непосредственно в объект, если они являются полями класса. Это избавляет от накладных расходов на выделение памяти в куче и работу сборщика мусора (GC).
  2. Семантика присваивания: При присваивании одной переменной-структуры другой (structA = structB) или при передаче структуры в метод по значению, происходит полное побитовое копирование всех её данных. Изменение копии никак не влияет на оригинал (в отличие от классов, где копируется только ссылка).
  3. Наследование: Структуры неявно наследуются от System.ValueType. Они не поддерживают наследование от других структур или классов (они неявно sealed), и от них нельзя унаследоваться. Однако структуры могут реализовывать интерфейсы (interface).
  4. Сборка мусора: Структуры в стеке уничтожаются мгновенно и детерминированно при выходе из области видимости (выходе из метода).

Когда использовать: Структуры рекомендуется применять для маленьких, логически неделимых и желательно неизменяемых (immutable) наборов данных, размер которых не превышает 16-24 байт (например: DateTime, Point, Color, Vector3). Если размер структуры большой, постоянное копирование значений при передаче в методы приведет к падению производительности (если не использовать модификаторы ref или in).

19. Пространства имен (namespace)

Определение: Пространство имен (namespace) — это механизм логической группировки связанных классов, структур, интерфейсов, перечислений и делегатов. Он предотвращает конфликты имен (naming collisions) в крупных проектах или при подключении сторонних библиотек.

Синтаксис и особенности:

  • Объявление:
    namespace Company.Project.Network 
    {
        class Client { }
    }
  • Доступ к типам: Чтобы использовать класс Client извне его пространства имен, необходимо либо указать его полное имя (Company.Project.Network.Client), либо импортировать пространство имен с помощью директивы using в начале файла: using Company.Project.Network;.
  • Вложенность: Пространства имен могут быть вложенными друг в друга как физически (один блок внутри другого), так и через точку в названии (как показано выше).
  • Алиасы (Псевдонимы): Директива using позволяет создавать псевдонимы для длинных типов или разрешения конфликтов (если в двух namespace есть класс с одинаковым именем): using NetClient = Company.Project.Network.Client;.
  • Современный C# (Начиная с версии 10.0):
    • File-scoped namespaces: Позволяет объявить пространство имен на весь файл без фигурных скобок namespace Company.Project;, что экономит отступы (indentation).
    • Global using: Директива global using System; позволяет импортировать пространство имен один раз на весь проект, чтобы не писать его в каждом отдельном файле.

20. Области видимости и Модификаторы доступа

Область видимости (Scope) — это часть программы (блок кода), в пределах которой переменная или тип доступны для использования. В C# области видимости строго иерархичны и определяются фигурными скобками {} (уровень пространства имен, уровень класса, уровень метода, уровень блока if/while). Переменная, объявленная во внутреннем блоке, невидима снаружи.

На уровне типов (классов/структур) и их членов (полей/методов) область видимости жестко контролируется Модификаторами доступа (Access Modifiers):

  1. private: Доступен только внутри текущего класса или структуры. Это модификатор по умолчанию для всех членов класса (если не указано иное). Обеспечивает строгую инкапсуляцию.
  2. public: Отсутствие ограничений. Доступен из любого места программы и из других сборок (dll), ссылающихся на текущую.
  3. protected: Доступен внутри текущего класса, а также во всех классах-наследниках (даже если они находятся в другой сборке).
  4. internal: Доступен из любого места, но только в пределах текущей сборки (Assembly/Проекта). Это модификатор по умолчанию для самих классов (верхнего уровня).
  5. protected internal: Доступен текущей сборке ИЛИ в классах-наследниках в других сборках (комбинация “ИЛИ”).
  6. private protected: (Введено в C# 7.2). Доступен только классам-наследникам, которые находятся строго в той же сборке (комбинация “И”).

21. Перегрузка методов (Method Overloading)

Определение: Перегрузка методов — это механизм (реализация статического полиморфизма), позволяющий объявлять в одном классе несколько методов с одинаковым именем, но с разной сигнатурой.

Сигнатура метода в C# включает в себя:

  1. Имя метода.
  2. Количество параметров.
  3. Типы параметров.
  4. Порядок следования параметров.
  5. Модификаторы параметров (ref, out, in).

Правила перегрузки: Компилятор разрешает вызов перегруженного метода на этапе компиляции (Early Binding), анализируя аргументы, переданные при вызове.

  • Внимание: Возвращаемый тип метода не является частью сигнатуры. Вы не можете создать два метода с одинаковыми параметрами, отличающиеся только тем, что один возвращает int, а другой double.
  • Наличие модификаторов ref или out делает сигнатуру отличной от метода без модификаторов. Однако нельзя перегрузить методы, отличающиеся только тем, что в одном стоит ref, а в другом out.
  • Модификатор params не влияет на разрешение перегрузки.

Назначение: Делает интерфейс класса более интуитивно понятным (например, метод Console.WriteLine() имеет 18 перегрузок, принимающих string, int, bool, double и т.д., что избавляет программиста от необходимости запоминать методы вроде WriteLineInt(), WriteLineString()).

22. Указатель this

Определение: Ключевое слово this — это зарезервированная неявная ссылка, доступная внутри нестатических методов, свойств и конструкторов класса (или структуры). Она указывает на текущий экземпляр объекта, для которого был вызван этот метод.

Практическое применение this в C#:

  1. Разрешение неоднозначности имен (Shadowing): Если имя параметра конструктора совпадает с именем поля класса, this помогает компилятору понять, где поле, а где аргумент:
    public Person(string name) {
        this.name = name; // this.name - поле объекта, name - параметр метода
    }
  2. Передача текущего объекта в другие методы: EventBus.Register(this);
  3. Вызов других конструкторов того же класса (Constructor Chaining): Позволяет избежать дублирования кода инициализации.
    public Person() : this("Unknown") { } // Вызовет конструктор с параметром string
  4. Создание Индексаторов (Indexers): Позволяет обращаться к объекту как к массиву: public int this[int index] { get { return arr[index]; } }.
  5. Объявление методов расширения (Extension Methods): Модификатор this перед первым параметром статического метода указывает компилятору, что метод “расширяет” указанный тип. public static void Print(this string str) { ... }.

Ограничение: Слово this недоступно в static методах и свойствах, так как статические члены принадлежат самому типу (классу), а не конкретному экземпляру объекта, и физически не привязаны ни к какому участку памяти с данными объекта.


Вид графа

Создано с помощью Quartz v4.5.2 © 2026

  • GitHub
  • Discord Community