2008-09-18 3 views
10

Предположим, что мы имеем:Являются ли делегаты не только сокращенными интерфейсами?

interface Foo 
{ 
bool Func(int x); 
} 

class Bar: Foo 
{ 
    bool Func(int x) 
    { 
    return (x>0); 
    } 
} 

class Baz: Foo 
{ 
    bool Func(int x) 
    { 
    return (x<0); 
    } 
} 

Теперь мы можем бросить вокруг бара и Баз как Фоос и вызвать их методы Func.

Делегаты упростить это немного:

delegate bool Foo(int x); 

bool Bar(int x) 
{ 
return (x<0); 
} 

bool Baz(int x) 
{ 
return (x>0); 
} 

Теперь мы можем бросить вокруг бара и Баз в качестве делегатов Foo.

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

ответ

14

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

Более короткий, более сжатый код также является достойным преимуществом.

+0

Интересно отметить, что делегаты могут получить доступ к членам. Метод класса, который должен быть передан, может легко действовать как курьер для результирующих данных, но прямой доступ - это гораздо более быстрый способ сделать это. – 2008-09-18 19:38:26

1

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

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

Взгляните на List<> class with the Find method. Теперь вы можете определить, что определяет, является ли что-то совпадением или нет, не требуя элементов, содержащихся в классе, для реализации IListFindable или чего-то подобного.

1

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

0

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

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

1

Можно думать делегат в качестве интерфейса для метода, который определяет, какие аргументы и типа возвращаемого значения методы должна соответствовать делегату

0

Да, делегат можно рассматривать как интерфейс с одним методом.

6

С точки зрения Software Engineering вы правы, делегаты очень похожи на функциональные интерфейсы, поскольку они прототип функционального интерфейса.

Их также можно использовать в одном и том же виде: вместо передачи всего класса, содержащего необходимый вам метод, вы можете передать только делегат. Это экономит массу кода и создает гораздо более читаемый код.

Кроме того, с появлением лямбда-выражений теперь они также могут быть легко определены на лету, что является огромным бонусом. Хотя ВОЗМОЖНО строить классы «на лету» на C#, это действительно огромная боль в прикладе.

Сравнение двух - интересная концепция. Я ранее не рассматривал, насколько похожи идеи из практики и структуры структурирования.

3

Делегат действительно имеет много общего с ссылкой на интерфейс, которая имеет единственный метод с точки зрения вызывающего.

В первом примере Baz и Bar являются классами, которые могут быть унаследованы и инстанцированы. Во втором примере Baz и Bar являются методами.

Вы не можете применять ссылки на интерфейс только для любого класса, который соответствует договору интерфейса. Класс должен явно объявить, что он поддерживает интерфейс. Вы можете применить ссылку делегата к любому методу, который соответствует сигнатуре.

Вы не можете включать статические методы в контракт интерфейса. (Хотя вы можете использовать статические методы с помощью методов расширения). Вы можете обратиться к статическим методам с помощью ссылки на делегат.

0

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

Делегаты были вдохновлены (частично) из-за того, что черное искусство указателей метода на C++ является неадекватным для определенных целей. Классическим примером является реализация механизма передачи сообщений или обработки событий. Делегаты позволяют вам определять подпись метода без каких-либо знаний о типах или интерфейсах класса. Я мог бы определить делегат «void eventHandler (Event * e)» и вызывать его на любом классе, который его реализовал.

Для ознакомления с этой классической проблемой и почему делегаты желательны read this, а затем this.

0

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

Смежные вопросы