Подтвердить что ты не робот

Зачем нам делегаты С#

Я никогда не понимаю, почему нам нужны делегаты? Я знаю, что они являются неизменяемыми ссылочными типами, которые содержат ссылку на метод, но почему мы не можем просто вызвать метод напрямую, а не вызвать его через делегат?

Спасибо

4b9b3361

Ответ 1

Конечно, вы можете вызывать метод непосредственно на объекте, но учитывать следующие сценарии:

  • Вы хотите вызвать серию методов, используя один делегат, не записывая много вызовов методов.
  • Вы хотите элегантно внедрить систему на основе событий.
  • Вы хотите вызывать два метода одинаковыми в подписи, но находятся в разных классах.
  • Вы хотите передать метод в качестве параметра.
  • Вы не хотите писать много полиморфного кода, как в LINQ, вы можете предоставить много реализации методу Select.

Ответ 2

Простой ответ: код, необходимый для выполнения действия, не знает метода вызова при его написании. Вы можете только вызвать метод напрямую, если знаете, во время компиляции, какой метод вызывать, не так ли? Поэтому, если вы хотите абстрагироваться от идеи "выполнить действие X в соответствующее время", вам нужно некоторое представление о действии, так что метод, вызывающий действие, не должен заранее знать точную реализацию.

Например:

  • Enumerable.Select в LINQ не может знать проекцию, которую вы хотите использовать, если вы не сообщите ей
  • Автор Button не знал, что вы хотите, чтобы действие было, когда пользователь нажимает на него.
  • Если новая тема только когда-либо делала одно, это было бы довольно скучно...

Это может помочь вам подумать о том, что делегаты являются как интерфейсы с одним методом, но с большим количеством синтаксиса языка, чтобы сделать их простыми в использовании, и фанковая поддержка асинхронного выполнения и многоадресной рассылки.

Ответ 3

Поскольку у вас может не быть еще написанного метода или вы разработали свой класс таким образом, чтобы пользователь мог решить, какой метод (который пользователь написал), пользователь хочет выполнить ваш класс.

Они также делают некоторые проекты более чистыми (например, вместо оператора switch, где вы вызываете разные методы, вы вызываете переданный делегат), и проще понять и разрешить расширение кода без его изменения (подумайте OCP).

Делегаты также являются основой системы событий - запись и регистрация обработчиков событий без делегатов будет намного сложнее, чем с ними.

Обратитесь к другим делегатам Action и Func в Linq - это вряд ли будет так же полезно без них.

Сказав это, никто не заставляет вас использовать делегатов.

Ответ 4

  • Делегаты поддерживают события
  • Делегаты предоставляют вашей программе способ выполнения методов, не зная точно, что эти методы находятся во время компиляции.

Ответ 5

Подумайте о указателях функций C/С++ и о том, как вы обрабатываете функции обработки событий javascript как "данные" и передаете их. В языке Delphi также существует процедурный тип. За кулисами, делегат С# и лямбда-выражения, и все эти вещи по существу являются одной и той же идеей: код как данные. И это составляет основу для функционального программирования.

Ответ 6

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

Без поддержки компилятора для этой методики исходный код должен быть довольно отвратительным. Если бы компилятор мог автоматически генерировать собственные вложенные классы, все могло бы быть довольно чистым. Скорость отправки для псевдо-делегатов, вероятно, обычно была бы медленнее, чем у обычных делегатов, но если псевдо-делегаты были интерфейсом, а не абстрактным базовым классом, класс, который должен только сделать псевдо-делегат для одного метода данной подписи, реализовать соответствующий интерфейс псевдоделегата; экземпляр класса затем может быть передан любому коду, ожидающему псевдо-делегата этой подписи, избегая необходимости создания дополнительного объекта. Кроме того, хотя количество классов, которые нужно было бы использовать при использовании псевдо-делегатов, было бы больше, чем при использовании "реальных" делегатов, каждому псевдо-делегату нужно было бы только один экземпляр объекта.

Ответ 7

Вы попросили пример того, почему вы передадите функцию в качестве параметра, у меня есть идеальный вариант, и я подумал, что это может помочь вам понять, это довольно академично, но показывает использование. Скажем, у вас есть метод ListResults() и метод getFromCache(). Вместо этого у вас много проверок, если кеш равен нулю и т.д. Вы можете просто передать любой метод getCache, а затем вызывать его только в том случае, если кеш пуст внутри метода getFromCache:

_cacher.GetFromCache(delegate { return ListResults(); }, "ListResults");

public IEnumerable<T> GetFromCache(MethodForCache item, string key, int minutesToCache = 5)
    {
        var cache = _cacheProvider.GetCachedItem(key);
        //you could even have a UseCache bool here for central control
        if (cache == null)
        {
            //you could put timings, logging etc. here instead of all over your code
            cache = item.Invoke();
            _cacheProvider.AddCachedItem(cache, key, minutesToCache);
        }            

        return cache;
    }

Ответ 8

Вы можете думать о них как о конструкции, подобной указателям на функции в C/С++. Но они больше, чем в С#. Подробности.