Ответ
Делегат в C# — это ссылочный тип. Экземпляр делегата создается в управляемой куче (heap), а переменная делегата хранит ссылку на этот объект.
Почему это важно и как работает:
- Ссылочная семантика: При присваивании одной переменной делегата другой копируется ссылка, а не сам объект делегата. Обе переменные начинают указывать на один и тот же экземпляр в куче.
- Мультикаст-делегаты: Делегаты поддерживают объединение (
+,+=), что позволяет создавать цепочки вызовов. Это реализовано через создание нового объекта делегата в куче, который содержит список вызовов (invocation list). - Сравнение: При использовании
==или.Equals()для делегатов сравниваются не только ссылки, но и целевые объекты и методы, что делает проверку логически осмысленной.
Пример:
// Объявление типа делегата
public delegate void LogMessage(string message);
class Program
{
static void LogToConsole(string msg) => Console.WriteLine($"[CONSOLE] {msg}");
static void LogToFile(string msg) => System.IO.File.AppendAllText("log.txt", msg + "n");
static void Main()
{
// Создание экземпляра делегата (ссылочного типа) в куче
LogMessage logger = LogToConsole;
logger("App started"); // Вызов через делегат
// Добавление второго метода. Оператор += создает НОВЫЙ объект делегата в куче.
logger += LogToFile;
logger("Data processed"); // Теперь вызовутся оба метода
// Переменная 'anotherLogger' теперь ссылается на тот же объект, что и 'logger'
LogMessage anotherLogger = logger;
}
}
Таким образом, хотя синтаксис работы с делегатами может напоминать работу с методами, технически это полноценные объекты ссылочного типа со своей внутренней структурой.