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

Делегаты и интерфейсы в С#

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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
    }
}

Ответ 3

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

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

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

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

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

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

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

От Делегирует Vs-интерфейсы в С#:

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

Ответ 4

Делегаты и интерфейсы представляют собой два разных понятия на С#.

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

Ответ 5

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

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

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

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