Uchyoba

Home

❯

Учёба

❯

Теория

❯

2.1.2026

❯

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

❯

Экзамен

Экзамен

15 сент. 2026 г.время чтения ~18 мин.

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

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

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

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

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

  • Реализация в C#: Обозначается двоеточием: class Derived : Base. В C# поддерживается только множественное наследование интерфейсов, но множественное наследование реализаций (классов) запрещено.

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

  • Динамический полиморфизм: В C# родительский класс объявляет метод как virtual (или abstract), а класс-наследник переопределяет его логику с помощью ключевого слова override.

Подробный пример синтаксиса:

// 1. ИНКАПСУЛЯЦИЯ: Скрываем поле balance, даем доступ через методы
public class BankAccount 
{
    private decimal balance; // Скрытое состояние
 
    public void Deposit(decimal amount) 
    {
        if (amount > 0) balance += amount; // Защита от некорректных данных
    }
    public decimal GetBalance() => balance;
}
 
// 2. НАСЛЕДОВАНИЕ: Класс Animal - базовый, Dog - наследник
public class Animal 
{
    public string Name { get; set; }
    
    // Ключевое слово virtual разрешает переопределение метода
    public virtual void Speak() 
    {
        Console.WriteLine("Животное издает звук");
    }
}
 
public class Dog : Animal 
{
    // 3. ПОЛИМОРФИЗМ: Переопределяем поведение метода
    public override void Speak() 
    {
        Console.WriteLine($"{Name} говорит: Гав!");
    }
}
 
// Использование полиморфизма
Animal myPet = new Dog { Name = "Шарик" };
myPet.Speak(); // Выведет "Шарик говорит: Гав!", хотя тип переменной Animal

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

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

Объект (Object / Instance) Объект — это конкретный экземпляр класса, созданный в оперативной памяти (в куче - Heap) с помощью оператора new.

Подробный пример синтаксиса:

// Объявление класса (чертеж)
public class Car 
{
    // Поля (состояние объекта)
    public string Model;
    public int Year;
 
    // Конструктор (вызывается при создании объекта)
    public Car(string model, int year) 
    {
        Model = model;
        Year = year;
    }
 
    // Метод (поведение)
    public void Drive() 
    {
        Console.WriteLine($"Машина {Model} ({Year}) поехала!");
    }
}
 
class Program
{
    static void Main()
    {
        // Создание объекта (инстанцирование) с помощью оператора new
        // myCar - это ссылка в стеке, указывающая на данные в куче
        Car myCar = new Car("Toyota", 2022);
        
        // Обращение к методу объекта
        myCar.Drive(); // Вывод: Машина Toyota (2022) поехала!
    }
}

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

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

1. Через параметр метода Main: Массив args содержит переданные аргументы, начиная с первого пользовательского аргумента.

2. Через класс Environment: Метод Environment.GetCommandLineArgs() возвращает массив, где нулевой индекс [0] — это всегда путь к исполняемому файлу программы.

Подробный пример синтаксиса: Запуск программы: dotnet run myFile.txt --force

class Program
{
    // Способ 1: Через параметры Main
    static void Main(string[] args)
    {
        Console.WriteLine("=== Способ 1: массив args ===");
        if (args.Length > 0)
        {
            for (int i = 0; i < args.Length; i++)
            {
                // Выведет: [0]: myFile.txt, [1]: --force
                Console.WriteLine($"Аргумент [{i}]: {args[i]}");
            }
        }
 
        // Способ 2: Через класс Environment (доступен в любом месте кода)
        Console.WriteLine("\n=== Способ 2: Environment ===");
        string[] envArgs = Environment.GetCommandLineArgs();
        
        // Выведет путь к .dll/.exe файлу
        Console.WriteLine($"Путь к программе: {envArgs[0]}"); 
        // Выведет myFile.txt
        Console.WriteLine($"Первый аргумент: {envArgs[1]}"); 
    }
}

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

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

Подробный пример синтаксиса: Плохой код (всё в одном месте):

public class BadApp {
    public void DoEverything() {
        // 1. Читает из БД
        string data = "SELECT * FROM Users"; 
        // 2. Делает расчет
        string parsed = data + " processed";
        // 3. Выводит на экран
        Console.WriteLine(parsed);
    }
}

Хороший код (разделение интересов):

// Слой 1: Работа с данными (Data Access)
public class UserRepository 
{
    public string GetUserFromDb() => "John Doe";
}
 
// Слой 2: Бизнес-логика (Business Logic)
public class UserService 
{
    private UserRepository _repo = new UserRepository();
    
    public string FormatUserName() 
    {
        string name = _repo.GetUserFromDb();
        return $"User: {name.ToUpper()}"; // Логика обработки
    }
}
 
// Слой 3: Представление (UI / View)
public class UserConsoleView 
{
    private UserService _service = new UserService();
    
    public void ShowUser() 
    {
        // UI ничего не знает о БД, он только выводит строку
        Console.WriteLine(_service.FormatUserName());
    }
}

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

В C# консольный I/O осуществляется через статический класс System.Console. Существует три основных способа форматирования: String.Format, конкатенация и современная строковая интерполяция (через знак $).

Подробный пример синтаксиса:

class Program
{
    static void Main()
    {
        // --- ВВОД ---
        Console.Write("Введите ваше имя: ");
        string name = Console.ReadLine(); // Читаем строку до Enter
 
        Console.Write("Введите ваш возраст: ");
        int age = int.Parse(Console.ReadLine());
 
        double price = 1250.50;
 
        // --- ВЫВОД И ФОРМАТИРОВАНИЕ ---
        // 1. Композитное форматирование (устаревающий подход)
        Console.WriteLine("Привет, {0}! Тебе {1} лет.", name, age);
 
        // 2. Строковая интерполяция (современный подход со знаком $)
        Console.WriteLine($"Привет, {name}! Тебе {age} лет.");
 
        // 3. Спецификаторы формата внутри интерполяции
        Console.WriteLine($"Цена товара: {price:C}"); // Вывод валюты (напр. 1 250,50 ₽)
        Console.WriteLine($"Число Пи: {Math.PI:F2}"); // Фиксированная точка: 3.14
        Console.WriteLine($"Возраст (с нулями): {age:D4}"); // Добивка нулями: 0025
 
        // Считывание одной клавиши без нажатия Enter
        Console.WriteLine("Нажмите любую клавишу для выхода...");
        Console.ReadKey();
    }
}

6. Методы

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

Подробный пример синтаксиса:

class MathUtils
{
    // 1. Обычный метод (передача по значению)
    public int Add(int a, int b) 
    {
        return a + b;
    }
 
    // 2. Expression-bodied метод (сокращенный синтаксис)
    public int Multiply(int a, int b) => a * b;
 
    // 3. Параметр OUT: метод возвращает bool, а результат вычисления кладет в out-переменную
    public bool TryDivide(int a, int b, out int result)
    {
        if (b == 0) 
        {
            result = 0; // Обязаны присвоить значение до выхода!
            return false;
        }
        result = a / b;
        return true;
    }
 
    // 4. Параметр REF: передача адреса памяти, метод меняет саму исходную переменную
    public void Swap(ref int x, ref int y)
    {
        int temp = x;
        x = y;
        y = temp;
    }
 
    // 5. Необязательные и именованные параметры
    public void PrintInfo(string name, int age = 18) // age по умолчанию = 18
    {
        Console.WriteLine($"{name}, {age}");
    }
}
 
// Использование:
MathUtils utils = new MathUtils();
 
// Вызов метода с out
if (utils.TryDivide(10, 2, out int divResult)) 
    Console.WriteLine($"Результат: {divResult}"); // Выведет 5
 
// Вызов метода с ref (переменные должны быть инициализированы)
int val1 = 5, val2 = 10;
utils.Swap(ref val1, ref val2); // Теперь val1 = 10, val2 = 5
 
// Именованные параметры
utils.PrintInfo(age: 25, name: "Ivan");

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

1. Цикл for — классический цикл со счетчиком. Выполняется, пока истинно условие. 2. Цикл foreach — перебирает элементы коллекций. Элемент цикла доступен только для чтения (read-only), и коллекцию нельзя менять во время перебора.

Подробный пример синтаксиса:

int[] numbers = { 10, 20, 30, 40, 50 };
 
// === ЦИКЛ FOR ===
Console.WriteLine("Цикл for:");
// инициализация ; условие ; итерация
for (int i = 0; i < numbers.Length; i++)
{
    // В for можно изменять элементы массива по индексу
    if (numbers[i] == 30) 
        numbers[i] = 99; 
        
    Console.WriteLine($"Индекс {i}: {numbers[i]}");
}
 
// === ЦИКЛ FOREACH ===
Console.WriteLine("\nЦикл foreach:");
foreach (int num in numbers)
{
    // num = 100; // ОШИБКА КОМПИЛЯЦИИ: num доступна только для чтения
    Console.WriteLine($"Значение: {num}");
}

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

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

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

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

Подробный пример синтаксиса:

// === ЦИКЛ WHILE ===
int count = 0;
Console.WriteLine("Цикл while:");
while (count < 3) 
{
    Console.WriteLine($"Счетчик: {count}");
    count++;
}
 
// === ЦИКЛ DO/WHILE ===
string password;
Console.WriteLine("\nЦикл do/while:");
do 
{
    // Этот блок выполнится минимум один раз, даже если пароль сразу верный
    Console.Write("Введите пароль (123): ");
    password = Console.ReadLine();
} 
while (password != "123"); // Проверка в конце. Обязательна точка с запятой!
 
Console.WriteLine("Доступ разрешен.");

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

Основные конструкции ветвления в C#.

  • if...else проверяет логическое выражение (bool).
  • switch сравнивает значение с набором констант (или паттернов). В C# запрещено проваливание между непустыми блоками case (обязателен break).

Подробный пример синтаксиса:

int temp = 15;
 
// === КОНСТРУКЦИЯ IF...ELSE ===
if (temp > 25) 
{
    Console.WriteLine("Жарко");
} 
else if (temp >= 10 && temp <= 25) 
{
    Console.WriteLine("Тепло"); // Сработает этот блок
} 
else 
{
    Console.WriteLine("Холодно");
}
 
// === КЛАССИЧЕСКИЙ SWITCH ===
int day = 3;
switch (day)
{
    case 1:
        Console.WriteLine("Понедельник");
        break; // Обязательный выход
    case 2:
    case 3: // Проваливание разрешено только для пустых case
        Console.WriteLine("Вторник или Среда");
        break;
    default:
        Console.WriteLine("Другой день");
        break;
}
 
// === СОВРЕМЕННОЕ ВЫРАЖЕНИЕ SWITCH (C# 8.0+) ===
// Возвращает значение напрямую
string result = day switch 
{
    1 => "Понедельник",
    2 or 3 => "Вторник или Среда",
    _ => "Другой день" // _ заменяет default
};
Console.WriteLine(result);

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

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

Подробный пример синтаксиса:

// 12 в двоичном: 0000 1100
// 10 в двоичном: 0000 1010
int a = 12; 
int b = 10;
 
// a & b: 0000 1100
//      & 0000 1010
// ----------------
// Итог:  0000 1000 (это 8 в десятичной)
int result = a & b; 
Console.WriteLine(result); // Выведет 8
 
// ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ: Проверка на четность
// Последний бит нечетного числа всегда 1. Маска "1" обнулит все биты кроме последнего.
int number = 7; // 0000 0111
if ((number & 1) == 1) 
{
    Console.WriteLine("Число нечетное");
}

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

Поразрядное (битовое) ИЛИ (OR) обозначается символом |. Результат равен 0 только если оба бита равны 0. Если хотя бы один бит 1, результат будет 1. Применяется для установки (включения) битов или комбинирования флагов.

Подробный пример синтаксиса:

// 12 в двоичном: 0000 1100
// 10 в двоичном: 0000 1010
int a = 12; 
int b = 10;
 
// a | b: 0000 1100
//      | 0000 1010
// ----------------
// Итог:  0000 1110 (это 14 в десятичной)
int result = a | b; 
Console.WriteLine(result); // Выведет 14
 
// ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ: Установка флагов (комбинирование прав)
[Flags] // Атрибут для работы с битовыми масками
enum FileAccess { None = 0, Read = 1, Write = 2, Execute = 4 }
 
// Даем пользователю права на чтение (1) и запись (2)
FileAccess userAccess = FileAccess.Read | FileAccess.Write; 
Console.WriteLine((int)userAccess); // Выведет 3 (0011 в двоичном)

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

Поразрядное исключающее ИЛИ (XOR) обозначается символом ^. Результат равен 1, если соответствующие биты операндов различны. Результат равен 0, если биты одинаковы. Применяется для инвертирования битов по маске и в простейшей криптографии.

Подробный пример синтаксиса:

// 12 в двоичном: 0000 1100
// 10 в двоичном: 0000 1010
int a = 12; 
int b = 10;
 
// a ^ b: 0000 1100
//      ^ 0000 1010
// ----------------
// Итог:  0000 0110 (это 6 в десятичной)
int result = a ^ b; 
Console.WriteLine(result); // Выведет 6
 
// ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ: Шифрование или инверсия битов
int key = 42;
int message = 150;
 
int encrypted = message ^ key; // Зашифровали
int decrypted = encrypted ^ key; // Расшифровали обратно (свойство XOR)
 
// ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ: Обмен значений переменных без третьей
int x = 5, y = 10;
x ^= y;
y ^= x;
x ^= y;
Console.WriteLine($"x={x}, y={y}"); // Выведет x=10, y=5

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

Поразрядное (битовое) НЕ (NOT) обозначается символом ~ (тильда). Это унарный оператор. Инвертирует каждый бит числа: заменяет все нули на единицы, а все единицы на нули. Применяется для создания обратных масок при сбросе (выключении) конкретных битов.

Подробный пример синтаксиса:

byte a = 12; // 0000 1100
 
// ~a: инверсия всех бит
// Итог: 1111 0011 (в знаковом int это даст отрицательное число -13)
int result = ~a; 
Console.WriteLine(result); // Выведет -13 (т.к. -x = ~x + 1)
 
// ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ: Сброс (выключение) конкретного бита
// Допустим, мы хотим выключить 3-й бит (значение 4) в числе 15 (0000 1111)
int mask = 4;        // 0000 0100
int inverse = ~mask; // 1111 1011
 
int data = 15;       // 0000 1111
data = data & ~mask; // Побитовое И с инвертированной маской
// Итог: 0000 1011 (это 11 в десятичной)
Console.WriteLine(data); // Выведет 11

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

Простой (одномерный) массив — это ссылочный тип данных (Reference Type), хранящий фиксированное количество элементов одного типа в непрерывном блоке памяти (в куче). Индексация начинается с нуля.

Подробный пример синтаксиса:

// 1. Объявление с выделением памяти (элементы заполняются нулями по умолчанию)
int[] numbers = new int[5]; 
numbers[0] = 10;
numbers[1] = 20;
 
// 2. Объявление с немедленной инициализацией (синтаксический сахар)
string[] names = { "Alice", "Bob", "Charlie" };
 
// 3. Получение размера массива
Console.WriteLine($"Размер массива: {names.Length}"); // 3
 
// 4. Современные фишки C# (Индексы и диапазоны)
string lastElement = names[^1]; // Выведет "Charlie" (^1 значит первый с конца)
string[] firstTwo = names[0..2]; // Создаст новый массив с "Alice", "Bob" (элемент 2 не включается)
 
// 5. Перебор массива
foreach (string name in names)
{
    Console.WriteLine(name);
}

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

Прямоугольный массив — это истинно многомерный массив, элементы которого организованы в виде матрицы. Каждая строка имеет строго одинаковую длину. Разделителем измерений в скобках выступает запятая [,].

Подробный пример синтаксиса:

// 1. Объявление двумерного массива (3 строки, 4 столбца)
int[,] matrix = new int[3, 4];
matrix[0, 0] = 5; // Присваивание
 
// 2. Объявление с немедленной инициализацией
int[,] grid = {
    { 1, 2, 3 },
    { 4, 5, 6 },
    { 7, 8, 9 }
};
 
// 3. Получение размеров матрицы
int totalElements = grid.Length; // 9
int rows = grid.GetLength(0);    // 3 (длина нулевого измерения - строк)
int cols = grid.GetLength(1);    // 3 (длина первого измерения - столбцов)
 
// 4. Перебор элементов прямоугольного массива
for (int i = 0; i < grid.GetLength(0); i++)
{
    for (int j = 0; j < grid.GetLength(1); j++)
    {
        Console.Write($"{grid[i, j]} \t");
    }
    Console.WriteLine(); // Переход на новую строку после вывода столбцов
}

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

Ломаный (зубчатый) массив (Jagged Array) — это массив массивов. Каждая его строка (внутренний массив) является самостоятельным объектом, поэтому строки могут иметь разную длину. Объявляется с помощью двойных квадратных скобок [][].

Подробный пример синтаксиса:

// 1. Объявление ломаного массива (3 строки)
int[][] jagged = new int[3][];
 
// 2. Инициализация каждой строки (выделение памяти под внутренние массивы)
jagged[0] = new int[4];         // Строка 0: 4 элемента
jagged[1] = new int[2];         // Строка 1: 2 элемента
jagged[2] = new int[] { 1, 2, 3 }; // Строка 2: 3 элемента сразу с инициализацией
 
// Присваивание значения
jagged[0][1] = 42;
 
// 3. Объявление с немедленной инициализацией всего массива
int[][] jagged2 = 
{
    new int[] { 1, 2 },
    new int[] { 3, 4, 5, 6 },
    new int[] { 7 }
};
 
// 4. Перебор ломаного массива
Console.WriteLine("Элементы ломаного массива:");
for (int i = 0; i < jagged2.Length; i++) // Проход по строкам (внешнему массиву)
{
    for (int j = 0; j < jagged2[i].Length; j++) // Проход по элементам i-й строки
    {
        Console.Write($"{jagged2[i][j]} ");
    }
    Console.WriteLine();
}

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

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

Подробный пример синтаксиса:

// 1. Базовое перечисление (по умолчанию тип int, отсчет с 0)
enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun }
 
// 2. Перечисление с явным указанием типа и значений
enum HttpCode : short 
{ 
    OK = 200, 
    NotFound = 404, 
    ServerError = 500 
}
 
// 3. Перечисление как битовые флаги (позволяет комбинировать значения)
[Flags]
enum Permissions : byte 
{ 
    None = 0,      // 0000
    Read = 1,      // 0001
    Write = 2,     // 0010
    Execute = 4,   // 0100
    All = 7        // 0111 (Read | Write | Execute)
}
 
class Program
{
    static void Main()
    {
        Days today = Days.Wed;
        // Каст (преобразование) в число
        Console.WriteLine($"День номер: {(int)today}"); // Выведет 2
        
        // Работа с битовыми флагами
        Permissions myRights = Permissions.Read | Permissions.Write; // 3 (0011)
        
        // Проверка флага встроенным методом (C# 4+)
        if (myRights.HasFlag(Permissions.Write))
        {
            Console.WriteLine("У вас есть права на запись");
        }
    }
}

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

Структура (struct) — это пользовательский значимый тип данных (Value Type).

  • Экземпляры структур хранятся в стеке (Stack), а не в куче.
  • При передаче структуры происходит полное побитовое копирование её значений (а не ссылки).
  • Не поддерживает наследование от других классов/структур (но может реализовывать интерфейсы).

Подробный пример синтаксиса:

// Объявление структуры
public struct Point
{
    public int X;
    public int Y;
 
    // Конструктор структуры
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
 
    public void Print() => Console.WriteLine($"({X}, {Y})");
}
 
class Program
{
    static void ModifyPoint(Point p)
    {
        p.X = 100; // Изменяется КОПИЯ структуры, оригинал останется нетронутым
    }
 
    static void Main()
    {
        Point p1 = new Point(10, 20); // Память выделяется в стеке
        Point p2 = p1; // ПРОИСХОДИТ ПОЛНОЕ КОПИРОВАНИЕ ДАННЫХ
 
        p2.X = 50; // p1.X останется равен 10
 
        ModifyPoint(p1); 
        p1.Print(); // Выведет (10, 20). Изменение внутри метода не сработало!
    }
}

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

Пространство имен (namespace) служит для логической группировки классов и предотвращения конфликтов имен. Чтобы использовать тип из другого пространства, нужно указать директиву using.

Подробный пример синтаксиса:

// Файл NetworkClient.cs
namespace App.Network 
{
    public class Client 
    {
        public void Connect() => Console.WriteLine("Connected");
    }
}
 
// Файл DatabaseClient.cs
// СОВРЕМЕННЫЙ СИНТАКСИС (C# 10+): File-scoped namespace (без фигурных скобок)
namespace App.Database;
 
public class Client 
{
    public void Save() => Console.WriteLine("Saved");
}
 
// Файл Program.cs
using App.Network; // Подключаем пространство имен
using DbClient = App.Database.Client; // Создаем алиас (псевдоним) для конкретного класса
 
class Program
{
    static void Main()
    {
        // Используем класс напрямую благодаря using App.Network;
        Client netClient = new Client();
        
        // Используем другой класс с таким же именем через алиас
        DbClient dbClient = new DbClient(); 
    }
}

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

Область видимости задается фигурными скобками {}. Модификаторы доступа контролируют видимость членов класса (полей, методов) из других частей программы.

Подробный пример синтаксиса:

public class BankAccount
{
    // Видно ТОЛЬКО внутри этого класса
    private decimal _balance; 
 
    // Видно внутри этого класса и во всех классах-наследниках
    protected string OwnerName; 
 
    // Видно во всем текущем проекте (Assembly), но скрыто от других DLL
    internal string BankCode; 
 
    // Доступно из любого места программы
    public void Deposit(decimal amount)
    {
        // Область видимости переменной fee ограничена этим методом
        decimal fee = 10; 
        
        if (amount > 1000)
        {
            // Область видимости переменной bonus ограничена блоком if
            decimal bonus = amount * 0.05m; 
            _balance += (amount + bonus - fee);
        }
        // Console.WriteLine(bonus); // ОШИБКА: bonus здесь не существует
    }
}

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

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

Подробный пример синтаксиса:

public class Printer
{
    // 1. Метод принимает строку
    public void Print(string text)
    {
        Console.WriteLine($"Текст: {text}");
    }
 
    // 2. ПЕРЕГРУЗКА: То же имя, но принимает целое число
    public void Print(int number)
    {
        Console.WriteLine($"Число: {number}");
    }
 
    // 3. ПЕРЕГРУЗКА: То же имя, но принимает два числа
    public void Print(int a, int b)
    {
        Console.WriteLine($"Сумма: {a + b}");
    }
 
    // public string Print(int number) { return "123"; } 
    // ОШИБКА: Возвращаемый тип не входит в сигнатуру. 
    // Нельзя перегрузить метод только изменением возвращаемого типа!
}
 
class Program
{
    static void Main()
    {
        Printer p = new Printer();
        p.Print("Hello"); // Вызовет 1-й метод
        p.Print(42);      // Вызовет 2-й метод
        p.Print(10, 20);  // Вызовет 3-й метод
    }
}

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

this — это скрытая ссылка на текущий экземпляр класса. Применяется для разрешения конфликтов имен, цепочек конструкторов и передачи текущего объекта в другие методы. Не работает в static методах.

Подробный пример синтаксиса:

public class Employee
{
    private string name;
    private int salary;
 
    // 1. РАЗРЕШЕНИЕ КОНФЛИКТА ИМЕН (Shadowing)
    // Имя параметра совпадает с именем поля
    public void SetName(string name)
    {
        this.name = name; // this.name - поле, name - параметр метода
    }
 
    // 2. ЦЕПОЧКА КОНСТРУКТОРОВ (Constructor chaining)
    // Вызывает другой конструктор этого же класса перед выполнением своего тела
    public Employee(string name) : this(name, 50000) 
    { 
        // ...
    }
 
    public Employee(string name, int salary)
    {
        this.name = name;
        this.salary = salary;
    }
 
    // 3. ПЕРЕДАЧА САМОГО СЕБЯ
    public void RegisterInCompany(Company company)
    {
        // Передаем текущий объект (себя) в метод другого класса
        company.AddEmployee(this); 
    }
}

Вид графа

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

  • GitHub
  • Discord Community