Все, что может быть сделано с делегатами, может быть сделано без них , но делегаты обеспечивают более чистый способ их выполнения. Если бы у кого-то не было делегатов, нужно было бы определить интерфейс или абстрактный базовый класс для каждой возможной сигнатуры функции, содержащей функцию Invoke (соответствующие параметры), и определить класс для каждой функции, которая должна была вызываться псевдо-делегатами. Этот класс наследовал бы соответствующий интерфейс для сигнатуры функции, содержал бы ссылку на класс, содержащий функцию, которую она должна была представлять, и метод, реализующий Invoke (соответствующие параметры), который вызывал бы соответствующую функцию в классе, к которому она относится ссылка. Если в классе Foo есть два метода Foo1 и Foo2, каждый из которых принимает один параметр, оба из которых могут вызываться псевдо-делегатами, то будет создано два дополнительных класса, по одному для каждого метода.
Без поддержки компилятором этой техники исходный код был бы довольно отвратительным. Если бы компилятор мог автоматически генерировать правильные вложенные классы, все могло бы быть довольно чисто. Скорость отправки для псевдо-делегатов, вероятно, будет, как правило, медленнее, чем с обычными делегатами, но если бы псевдо-делегаты были интерфейсом, а не абстрактным базовым классом, то класс, который должен создать псевдо-делегат только для одного метода данной подписи, реализовать соответствующий интерфейс псевдо-делегата; затем экземпляр класса может быть передан любому коду, ожидающему псевдо-делегата этой подписи, избегая необходимости создавать дополнительный объект. Кроме того, хотя количество классов, которые могут понадобиться при использовании псевдо-делегатов, будет больше, чем при использовании «настоящих» делегатов, каждый псевдо-делегат должен будет содержать только один экземпляр объекта.