Что такое делегат? [закрыто]

152

Я смущен тем, какова реальная роль делегата?

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

Может кто-нибудь сказать мне лучшее определение, в одном предложении, с практическим примером?

Навид
источник
21
из любопытства, что вы ответили, чтобы мы могли рассказать вам, как вы можете это исправить?
Энтони Форлони
6
Мне интересно, что этот вопрос закрыт, но у него 126 голосов, и 65 человек отметили его как фаворита. Кажется, даже если он слишком широкий, это все еще очень хороший вопрос.
Богатый

Ответы:

171

Мне нравится думать о делегате как о «указателе на функцию». Это восходит к дням C, но идея все еще держится.

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

Вот справочник по C #, на который вы можете посмотреть:

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

public static double CalcTotalMethod1(double amt)
{
    return amt * .014;
}

public static double CalcTotalMethod2(double amt)
{
    return amt * .056 + 42.43;
}

Мы могли бы объявить подпись делегата следующим образом:

public delegate double calcTotalDelegate(double amt);

И тогда мы могли бы объявить метод, который принимает делегат в качестве параметра, например:

public static double CalcMyTotal(double amt, calcTotalDelegate calcTotal)
{
    return calcTotal(amt);
}

И мы могли бы вызвать CalcMyTotalметод, передавая метод делегата, который мы хотели использовать.

double tot1 = CalcMyTotal(100.34, CalcTotalMethod1);
double tot2 = CalcMyTotal(100.34, CalcTotalMethod2);
Console.WriteLine(tot1);
Console.WriteLine(tot2);
DCP
источник
19
+1 за поклон простому, но эффективному указателю на функцию в C.
Эйден Белл,
3
Один вопрос связан с вашим ответом. Чем это действительно отличается от вызова функции обычным способом? Просто из-за этого это не известно во время выполнения?
Навид
1
@NAVEED - обратитесь к моему последнему редактированию, я включил пример. Что касается фактического вызова метода, он ничем не отличается от обычного вызова метода в моем примере выше (calcTotal (amt) вызывает делегат), но сила делегатов в том, что вы можете использовать их в качестве параметров, и т.д., когда вы хотите, чтобы метод мог иметь другое поведение. Есть много других вещей, для которых вы можете использовать их, это всего лишь простой пример. Надеюсь, это поможет.
2010 года
Он не известен во время выполнения и является связанной функцией, а не свободной функцией - назначение нестатического метода Fooделегату будет вызывать, this.Foo()а не статическую функцию, как это делал бы указатель на функцию (в C вы часто имеете дополнительный void*параметр для перейти thisк указателю на функцию)
Пит Киркхам
1
+1 за быстрый и эффективный пример установления сходства с указателями на функции в C / C ++. Очень признателен!
G21
19

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

некоторый код для демонстрации (записал это из памяти, чтобы синтаксис мог быть отключен)

delegate void delMyDelegate(object o);

private void MethodToExecute1(object o)
{
    // do something with object
}

private void MethodToExecute2(object o)
{
    // do something else with object
}

private void DoSomethingToList(delMyDelegate methodToRun)
{
    foreach(object o in myList)
        methodToRun.Invoke(o);
}

public void ApplyMethodsToList()
{
    DoSomethingToList(MethodToExecute1);
    DoSomethingToList(MethodToExecute2);
}
Младен Прайдич
источник
16

Взято отсюда

Q Что такое делегаты?
A Когда объект получает запрос, он может обработать сам запрос или передать запрос второму объекту для выполнения работы. Если объект решает передать запрос, вы говорите, что объект передал ответственность за обработку запроса второму объекту.

Или, как простой псевдо-пример: что-то отправляет запрос к object1. Затем объект1 пересылает запрос и себя объекту2 - делегату. object2 обрабатывает запрос и выполняет некоторую работу. (примечание: ссылка выше дает хорошие примеры)

Энтони Форлони
источник
Пример, приведенный в приведенной выше ссылке, не правильно указывает делегирование.
Hardik9850
4

Думайте о делегате как об упрощенной реализации шаблона Command.

Виталий Липчинский
источник
4

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

Простой делегат

Declaration of delegate:
delegate-modifier delegate return-type delegate-name(parameters)
Implementation of delegate:
Delegate-name delegate-object=new Delegate-name(method of class)

http://knowpacific.wordpress.com/2012/01/26/delegate/

Сандип Шехават
источник
2

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

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

Delegates are like C++ function pointers but are type safe.
Delegates allow methods to be passed as parameters.
Delegates can be used to define callback methods.
Delegates can be chained together; for example, multiple methods can be called on a single event.
Methods do not have to match the delegate signature exactly.

открытый делегат type_of_delegate Delegate_name () // Объявление

You can use delegates without parameters or with parameter list
If you are referring to the method with some data type then the delegate which you are declaring should be in the same format. This is why it is referred to as type safe function pointer. Here I am giving an example with String.

В следующем примере показана операция делегата:

    namespace MyDelegate
    {
        class Program
        {
            private delegate void Show(string s);


            // Create a method for a delegate.
            public static void MyDelegateMethod(string me

ssage)
        {
            System.Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            Show p = MyDelegateMethod;
            p("My Delegate");
            p.Invoke("My Delegate");
            System.Console.ReadLine();
        }
    }
}

Что такое Multicast Delegate?

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

 delegate void MyMulticastDelegate(int i, string s);
 Class Class2
 {
  static void MyFirstDelegateMethod(int i, string s)
  {
    Console.WriteLine("My First Method");
  }

  static void MySecondDelegateMethod(int i, string s)
  {
    Console.WriteLine("My Second Method");
  }

  static void Main(string[] args)
  {
    MyMulticastDelegate Method= new MyMulticastDelegate(MyFirstDelegateMethod);
    Method+= new MyMulticastDelegate (MySecondDelegateMethod);
    Method(1,"Hi");             // Calling 2 Methodscalled
    Method-= new MyMulticastDelegate (MyFirstDelegateMethod);
    Method(2,"Hi");             //Only 2nd Method calling
  }
}

Здесь Delegate добавляется с помощью оператора + = и удаляется с помощью оператора - =.

Типы делегатов являются производными от класса Delegate в .NET Framework. Типы делегатов запечатаны - они не могут быть получены. Поскольку созданный делегат является объектом, его можно передать в качестве параметра или назначить свойству. Это позволяет методу принимать делегата в качестве параметра и вызывать его позже. Это известно как асинхронный обратный вызов.

Джом Джордж
источник
1

Отличное объяснение и практическая реализация шаблона делегата можно найти в классах пересылки коллекций Google (также шаблоне декоратора).

деревенщина
источник
1

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

button1.Click + = new System.EventHandler (button1_Click) System.EventHandler объявляется здесь как делегат. В .net Events работают над концепцией делегата (как нажатие кнопки)

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

http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx

Yogesh
источник
1

Объект делегата - это объект, к которому обращается другой объект, когда что-то происходит в этом объекте. Например, ваш ремонтник - ваш представитель, если что-то случится с вашей машиной. Вы идете к своему ремонтнику и просите его починить автомобиль для вас (хотя некоторые предпочитают ремонтировать автомобиль самостоятельно, в этом случае они являются их собственным представителем для своего автомобиля).


источник
1

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

1) является объектно-ориентированным

2) Тип безопасен, то есть он может указывать только на метод, и вы не можете прочитать необработанный адрес памяти, на который он указывает

3) Сильно типизирован. Он может указывать только на методы, соответствующие его сигнатурам.

4) Может указывать на более чем один метод одновременно.

Кулер для воды v2
источник
1

Делегаты в основном используются с мероприятиями.

Необходимость:

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

Пример :

  1. Консольное приложение - код может быть выполнен только во время запуска программы. (Написано внутри метода Main)
  2. Приложение Windows (программирование интерфейса пользователя) - код может быть выполнен при нажатии кнопки после запуска программы.

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

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

шатхар хан
источник
0

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

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

Простой пример:

SomeInterface
{
   public void doSomething();
}


SomeImplementation implements SomeInterface
{
   public void doSomething()
   {
      System.err.println("Was it good for you?");
   }

}


SomeCaller
{
   public void doIt(SomeInterface someInterface)
   {
      someInterface.doSomething();
   }
}

Теперь вы видите, что я могу использовать любую реализацию, какую захочу, в любое время без изменения кода в SomeCaller, поскольку передаваемый тип doIt()не конкретный, а скорее абстрактный, поскольку это интерфейс. В мире Java это часто выражается в парадигме службы, где вы вызываете службу (объект, рекламирующий себя как службу через определенный интерфейс), а затем служба обращается к делегатам, чтобы помочь ей выполнить свою работу. Методы службы называются грубозернистыми задачами (makePayment (), createNewUser () и т. Д.), В то время как внутренне это делает много, если тщательная работа выполняется посредством делегирования, причем типы делегатов являются интерфейсами, а не конкретными реализациями.

SomeService
{
    SomeInterface someImplementation = ... // assign here
    SomeOtherInterface someOtherImplementation = ... // okay, let's add a second

    public void doSomeWork()
    {
         someImplementation.doSomething();
         someOtherImplementation.doSomethingElse();
    }
}

(Примечание: способ назначения реализации выходит за рамки этого потока. Поиск инверсии управления и внедрение зависимостей.)

акварель
источник
-2

Хотя в действительности это не «указатель на функцию», делегат может выглядеть так, как будто это динамический язык, такой как PHP:



$func = 'foo';
$func();

function foo() {
    print 'foo';
}

или в JavaScript вы можете сделать что-то вроде:


var func = function(){ alert('foo!'); }
func();

mmattax
источник
2
Это не пример делегирования. В вашем примере вы используете то, что называется переменной функцией, которая в основном ищет функцию с тем же именем, что и строка, на которую ссылается переменная. Смотрите переменные функции: php.net/manual/en/functions.variable-functions.php
Акварель