Делегаты vs интерфейсы В C#

Я хотел бы задать этот вопрос, пока я пытаюсь в настоящее время углубиться в использование и цель делегатов, хотя, вероятно, он был задан в аналогичных формулировках.

Я знаю, что делегаты служат указателями функций, используемыми в C++. Дело в том, что в C# они служат в основном альтернативой интерфейсам и полиморфизму. Поскольку я могу создавать подклассы определенного класса и предоставлять им соответствующие методы для каждого из них, какое предложение делегаты в дополнение к этому? Существуют ли случаи, которые предусматривают их использование или просто улучшена ремонтопригодность кода при использовании делегатов? Вы бы порекомендовали их широкое развертывание через интерфейсы?

Я говорю исключительно о делегатах и я хочу, чтобы отличить свою роль от роли событий.

5 ответов


да, делегаты во многих отношениях похожи на интерфейсы с одним методом. Однако:

  • существует поддержка, встроенная в CLR для них
  • есть поддержка в рамках для них, в том числе мультикастовых способностей и асинхронного вызова
  • существует дополнительная поддержка языка C#/VB в виде преобразования групп методов, лямбда-выражений, анонимных методов
  • они уполномочены на события (т. е. события и делегаты являются своего рода совпадающая пара)
  • они имеют в виду тебя не необходимо реализовать интерфейс в отдельном классе для каждого экземпляра делегата, который вы хотите создать.

последний момент является самым важным - рассмотрим выражение LINQ:

var query = collection.Where(x => x > 5)
                      .Select(x => x * x);

а теперь представьте, если выразить логику x > 5 и x * x вам нужно было написать отдельный класс для каждого выражения и реализовать интерфейс: количество cruft против полезного кода было бы смешно. Теперь, конечно, язык мог бы были разработаны, чтобы разрешить преобразования из лямбда-выражений в реализации интерфейса через отдельные классы, но тогда вы все равно потеряете преимущество возможности просто написать отдельный метод и создать делегат с этим в качестве цели. Вы также все равно потеряете способности мультикаста.

как подобную мысль exercsise, рассмотреть циклических инструкций, таких как while и for. Мы действительно нужно ними когда у нас будет goto? Нет. Но жизнь намного лучше!--18-->С них. То же самое относится и к делегатам - и, действительно, к свойствам, событиям и т. д. Все они упрощают разработку.


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

void delegate XYZ(int p);

interface IXyz {
    void doit(int p);
}

class One {
    // All four methods below can be used to implement the XYZ delegate
    void XYZ1(int p) {...}
    void XYZ2(int p) {...}
    void XYZ3(int p) {...}
    void XYZ4(int p) {...}
}

class Two : IXyz {
    public void doit(int p) {
        // Only this method could be used to call an implementation through an interface
    }
}

С когда использовать делегаты вместо интерфейсов (MSDN):

делегаты и интерфейсы позволяют конструктору классов отделять объявления и реализацию типов. Данный интерфейс может быть унаследован и реализован любым классом или структурой. Делегат может быть создан для метода в любом классе, если метод соответствует сигнатуре метода для делегата. Ссылка на интерфейс или делегат может использоваться объектом, который не знает класс, реализующий метод interface или delegate. Учитывая эти сходства, когда дизайнер классов должен использовать делегат и когда он должен использовать интерфейс?

используйте делегат в следующих случаях:

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

используйте интерфейс в следующих обстоятельствах:

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

один хороший пример использования интерфейса одного метода вместо делегата -IComparable или общая версия,IComparable(Of T). IComparable объявляет метод CompareTo, который возвращает целое число, указывающее отношение меньше, равно или больше отношения между двумя объектами одного типа. IComparable смогите быть использовано как основа алгоритм сортировки. Хотя использование метода сравнения делегатов в качестве основы алгоритма сортировки было бы допустимым, он не идеален. Поскольку возможность сравнения принадлежит классу, а алгоритм сравнения не изменяется во время выполнения, интерфейс одного метода идеален.

С делегаты против интерфейсов в C#:

делегаты и интерфейсы-это два разных понятия в C#, но они разделяют общность. Обе делегаты и интерфейсы включают только декларацию. Реализация выполняется другим объектом программирования.


делегаты и интерфейсы-это два разных понятия в C#.

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


единственными реальными преимуществами делегатов над интерфейсами являются

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

когда .net не поддерживал дженерики, делегаты были существенной частью этого, так как объявление различных не-универсальных интерфейсов для каждой другой сигнатуры функции, которую нужно было бы передать, было бы неработоспособным. Если бы .net поддерживал дженерики с самого начала, делегаты не были бы необходимы, за исключением некоторых сценариев, связанных с отражением, и даже там, возможно, было бы наиболее полезно иметь тип Action<T,U> быть реализация IAction<T,U> (Так что код, который просто нуждается в чем-то он может Invoke будет использовать интерфейс). Подход, основанный на интерфейсе, потребовал бы создания классов с одним методом в случаях, когда классам необходимо создать делегаты, предоставляющие несколько методов, но устранил бы необходимость создания отдельных экземпляров делегатов во многих распространенных случаях, когда количество методов данной подписи, подлежащей представлению, точно одно.

кста, замена делегатов интерфейсами никоим образом не помешает созданию универсального метода объединения. Действительно, ковариация интерфейса может сделать такой метод лучше, чем существующий Delegate.Combine во многих отношениях. Реализация метода, аналогичного Delegate.Remove было бы в лучшем случае неуклюжим и раздражающим, но я не могу придумать никакой ситуации, кроме управления подпиской на события, которая потребовала бы использования Delegate.Remove, а подписку на события лучше всего обрабатывать с помощью других подходов в любом случае.