← Назад к вопросам

Каким типом данных является делегат?

1.0 Junior🔥 251 комментариев
#Основы C# и .NET

Комментарии (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#.