Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Делегаты в C#
Делегат — это ссылочный тип данных (reference type), который представляет собой типизированный указатель на метод. Делегат определяет сигнатуру метода (параметры и возвращаемый тип), и может указывать на любой метод с совпадающей сигнатурой.
Объявление делегата
// Объявление типа делегата
public delegate void NotifyDelegate(string message);
public delegate int MathDelegate(int a, int b);
public delegate bool FilterDelegate(int value);
Делегат — это класс, наследующий от System.MulticastDelegate, который наследует от System.Delegate. Это можно проверить:
var del = new NotifyDelegate(Console.WriteLine);
Console.WriteLine(del.GetType().BaseType); // System.MulticastDelegate
Console.WriteLine(del is Delegate); // true
Использование делегатов
public class Calculator
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
public int Multiply(int a, int b) => a * b;
}
// Создание делегата
var calc = new Calculator();
MathDelegate operation = calc.Add;
int result = operation(10, 5); // 15
Console.WriteLine(result);
// Переназначение
operation = calc.Subtract;
result = operation(10, 5); // 5
// Статический метод
operation = int.Parse; // Ошибка! Parse возвращает int, но принимает string
Многоадресные делегаты (Multicast)
public delegate void LogDelegate(string message);
public class Logger
{
public void LogToConsole(string msg) => Console.WriteLine($"[Console]: {msg}");
public void LogToFile(string msg) => File.AppendAllText("log.txt", msg);
public void LogToDatabase(string msg) => Console.WriteLine($"[DB]: {msg}");
}
var logger = new Logger();
LogDelegate log = logger.LogToConsole;
log += logger.LogToFile;
log += logger.LogToDatabase;
// Все три метода выполнятся по очереди
log("Important message");
// Удаление из цепи
log -= logger.LogToFile;
log("Another message"); // Выполнятся только первый и третий
Action и Func (встроенные делегаты)
// Action — не возвращает значение (void)
Action<string> greet = name => Console.WriteLine($"Hello, {name}");
greet("Alice"); // Hello, Alice
// Func — возвращает значение
Func<int, int, int> add = (a, b) => a + b;
int sum = add(5, 3); // 8
// Несколько параметров
Action<int, int, string> processOrder = (orderId, quantity, product) =>
{
Console.WriteLine($"Order {orderId}: {quantity}x {product}");
};
processOrder(1, 2, "Laptop");
Делегаты в событиях
public class Button
{
// Объявляем событие на основе делегата
public event EventHandler Click;
public void Press()
{
Console.WriteLine("Button pressed!");
// Вызываем все подписчиков
Click?.Invoke(this, EventArgs.Empty);
}
}
// Использование
var button = new Button();
button.Click += (sender, e) => Console.WriteLine("Handler 1");
button.Click += (sender, e) => Console.WriteLine("Handler 2");
button.Press();
// Output:
// Button pressed!
// Handler 1
// Handler 2
Сравнение с другими ссылочными типами
| Тип | Является ссылкой | Примеры |
|---|---|---|
| Класс | Да | string, List<T>, object |
| Делегат | Да | Action, Func, Custom delegates |
| Интерфейс | Нет (абстрактный тип) | IEnumerable, IDisposable |
| Структура | Нет (value type) | int, DateTime, struct |
| Массив | Да | int[], string[] |
Памяти и производительность
// Делегат хранится в куче
var delegate1 = new Action(() => Console.WriteLine("1"));
var delegate2 = delegate1; // delegate2 указывает на тот же объект
Console.WriteLine(ReferenceEquals(delegate1, delegate2)); // true
// При добавлении в многоадресный делегат создается новый объект
Action action = () => { };
var original = action;
action += () => { };
Console.WriteLine(ReferenceEquals(action, original)); // false!
Лямбда-выражения как делегаты
// Lambda = делегат в компактной форме
Func<int, int, int> multiply = (x, y) => x * y;
Action<string> print = msg => Console.WriteLine(msg);
// Это эквивалентно
Func<int, int, int> multiply2 = delegate(int x, int y) { return x * y; };
Ковариантность и контравариантность
public delegate object ObjectDelegate();
public delegate void StringDelegate(string arg);
// Ковариантность (более конкретный возвращаемый тип)
object GetString() => "Hello";
ObjectDelegate del = GetString; // OK
// Контравариантность (более общий параметр)
void AcceptObject(object arg) => Console.WriteLine(arg);
StringDelegate del2 = AcceptObject; // OK
Итого: Делегат — это ссылочный тип, который позволяет передавать методы как параметры, сохранять их в переменные и создавать цепи вызовов. Это основа для событий и функционального программирования в C#.