Если точнее, то делегат - это специализированный механизм на уровне языка (забронированный как string), по факту представляющий из себя class<T, ..., ...> с встроенным списком ссылок на функции (именно функции, даже если записывается метод), с уже предопереопределёнными операторами для работы с коллекцией ссылок и проверкой на null, когда коллекция пуста. Вызов делегата запускает цепочку вызовов сохранённых ссылок на функции в порядке сохранения, и если у делегата есть возвращаемый <T> - возвращается ответ от последней функции в цепочке.
События - по сути упрощённые делегаты (но не являются прямыми потомками таковых, а реализуются прямо в объекте, содержащем событие), чтобы создать событие, нужно сначала объявить его сигнатуру используя делегат. События ограничены тем, что их нельзя вызвать извне объекта, частью которого они являются, сам объект только может запустить своё событие, а событие в свою очередь может вызывать любые функции. События хоть и ограничены/упрощены, в сравнении с делегатами, но это позволило реализовать объявление событий на уровне интерфейсов.