Зачем нам нужны делегаты C#



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



спасибо

579   8  

8 ответов:

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

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

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

для пример:

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

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

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

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

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

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

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

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

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

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

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

вы спросили пример того, почему вы передадите функцию в качестве параметра, у меня есть идеальный и подумал, что это может помочь вам понять, это довольно академично, но показывает использование. Скажем, у вас есть метод 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;
    }

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

Comments

    Ничего не найдено.