Когда и почему использовать делегатов? [дубликат]

343
задан 6 revs, 5 users 78% 29 July 2019 в 22:45
поделиться

6 ответов

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

Делегат может рассматриваться как заполнитель для некоторого метода (ов).

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

Типичное использование, конечно, события. Все OnEventX делегируют методам, определяемым пользователем.

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

275
ответ дан 23 November 2019 в 00:33
поделиться

Delegates очень полезны, когда вы хотите объявить блок кода, который вы хотите передать. Например, при использовании общего механизма повторных попыток.

Псевдо:

function Retry(Delegate func, int numberOfTimes)
    try
    {
       func.Invoke();
    }
    catch { if(numberOfTimes blabla) func.Invoke(); etc. etc. }

Или когда Вы хотите сделать поздний анализ блоков кода, например, функции, где у Вас есть некоторое действие Преобразование , и хотите выполнить действие BeforeTransform и действие AfterTransform, которое Вы можете оценить внутри Вашей функции Преобразования, без необходимости знать, заполнено ли действие BeginTransform, или что оно должно преобразовывать.

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

.
29
ответ дан 23 November 2019 в 00:33
поделиться

Скажем, вы хотите написать процедуру для интеграции некоторой функции реального значения f (x) на каком-то интервале [a, b]. Скажем, мы хотим использовать для этого метод 3-Point Gaussian (любой сделает, конечно).

В идеале нам нужна какая-то функция, которая выглядит так:

// 'f' is the integrand we want to integrate over [a, b] with 'n' subintervals.
static double Gauss3(Integrand f, double a, double b, int n) {
  double res = 0;

  // compute result
  // ...

  return res;
}

Чтобы мы могли пройти в любом Integrand, f, и получить его определённый интеграл на замкнутом интервале.

Каким должен быть Integrand?

Без делегатов

Ну, без делегатов нам бы понадобился некий интерфейс с одним методом, скажем, eval, объявленный следующим образом:

// Interface describing real-valued functions of one variable.
interface Integrand {
  double eval(double x);
}

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

// Some function
class MyFunc1 : Integrand {
  public double eval(double x) {
    return /* some_result */ ;
  }
}

// Some other function
class MyFunc2 : Integrand {
  public double eval(double x) {
    return /* some_result */ ;
  }
}

// etc

Затем, чтобы использовать их в нашем методе Гаусса3, нам нужно вызвать его следующим образом:

double res1 = Gauss3(new MyFunc1(), -1, 1, 16);
double res2 = Gauss3(new MyFunc2(), 0, Math.PI, 16);

А Гауссу3 нужно сделать так, чтобы он выглядел следующим образом:

static double Gauss3(Integrand f, double a, double b, int n) {
  // Use the integrand passed in:
  f.eval(x);
}

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

С помощью Delegates

public delegate double Integrand(double x);

Теперь мы можем определить некоторые статические (или не статические) функции, придерживающиеся этого прототипа:

class Program {
   public delegate double Integrand(double x);   
   // Define implementations to above delegate 
   // with similar input and output types
   static double MyFunc1(double x) { /* ... */ }
   static double MyFunc2(double x) { /* ... */ }
   // ... etc ...

   public static double Gauss3(Integrand f, ...) { 
      // Now just call the function naturally, no f.eval() stuff.
      double a = f(x); 
      // ...
   }

   // Let's use it
   static void Main() {
     // Just pass the function in naturally (well, its reference).
     double res = Gauss3(MyFunc1, a, b, n);
     double res = Gauss3(MyFunc2, a, b, n);    
   }
}

Нет интерфейсов, нет неуклюжих .eval вещей, нет инстанцирования объектов, просто простой указатель функции, как использование, для простой задачи.

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

.
144
ответ дан 23 November 2019 в 00:33
поделиться

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

.
9
ответ дан 23 November 2019 в 00:33
поделиться

Обзор делегатов

Делегаты имеют следующие свойства:

  • Делегаты похожи на указатели функции C++, но безопасны по типу.
  • Делегаты позволяют передавать методы в качестве параметров.
  • Делегаты могут быть использованы для определения методов обратного вызова.
  • Делегаты могут быть связаны друг с другом; например, при одном событии может быть вызвано несколько методов.
  • Методы не обязательно должны точно совпадать с подписью делегата. Подробнее см. дисперсию Ковариаций и Контры.
  • C# версии 2.0 вводится понятие Анонимных Методов, которые позволяют передавать блоки кода в качестве параметров вместо отдельно определенного метода.
21
ответ дан 23 November 2019 в 00:33
поделиться

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

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

Создать делегата легко. Определите класс в качестве делегата с помощью ключевого слова "делегат". Затем укажите тип подписи.

3
ответ дан 23 November 2019 в 00:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: