Пожалуйста, объясните. NET делегатов - PullRequest
11 голосов
/ 19 марта 2010

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

public GetCustomers(Action<IEnumerable<Customer>,Exception> callBack)
{
}

Что это, и что я должен передать ему?

Ответы [ 9 ]

9 голосов
/ 19 марта 2010

ожидает функцию, которая принимает IEnumerable и Exception и возвращает void.

void SendExceptionToCustomers(IEnumerable<Customer> customers, Exception ex) {
   foreach(var customer in customers)
      customer.SendMessage(ex.Message);
}

GetCustomers(SendExceptionToCustomers);

Кстати, GetCustomers кажется ужасным названием для этой функции - она ​​требует действия, поэтому она больше похожа на DoSomethingToCustomers

РЕДАКТИРОВАТЬ в ответ на комментарий


Хорошо. Имеет смысл, так зачем теперь беспокоиться о наличии функции GetCustomer? Разве я не могу сделать то же самое с вашей функцией, если я просто переименую ее в GetCustomer?

Что здесь происходит, вызывающий может указать какое-то действие. Предположим, что GetCustomers реализован так:

public void GetCustomers(Action<Enumerable<Customer>, Exception> handleError) {
    Customer[] customerlist =  GetCustomersFromDatabase();
    try {
        foreach(var c in customerList) 
            c.ProcessSomething()
    } catch (Exception e) {
        handleError(customerList, e);
    }
}

тогда вы можете вызвать Getcustomers откуда-нибудь из программы командной строки и передать ее

GetCustomers((list, exception) => { 
    Console.WriteLine("Encountered error processing the following customers");
    foreach(var customer in list) Console.WriteLine(customer.Name);
    Console.WriteLine(exception.Message);
}); 

в то время как вы можете вызвать GetCustomers, например, из удаленного приложения, и передать его

Getcustomers((list, exception) => { 
    // code that emails me the exception message and customer list
})


Кроме того, комментарий Слака предлагает еще одну причину для параметра делегата - GetCustomers действительно получает клиентов, но асинхронно. Всякий раз, когда это делается для извлечения клиентов, он вызывает функцию, которую вы ей даете, либо со списком клиентов, либо с исключением, если произошло исключение.
3 голосов
/ 19 марта 2010

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

В вашем случае функция GetCustomers принимает в качестве параметра вторую функцию.

Вторая функция должна принимать два параметра типа IEnumerable<Customer> и Exception.

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

Например:

static void GetCustomersCallback(IEnumerable<Customer> customers, Exception ex) {
    //Do something...
}

//Elsewhere:
GetCustomers(new Action<IEnumerable<Customer>,Exception>(GetCustomersCallback));

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

GetCustomers(GetCustomersCallback);
2 голосов
/ 19 марта 2010
2 голосов
/ 19 марта 2010

это можно назвать лямбда

GetCustomers((cust, ex) => {
    //do something here}
);
1 голос
/ 19 мая 2010

Просто? Функциональные указатели

1 голос
/ 19 марта 2010

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

Сигнатура типа может быть сделана универсальной с использованием возможностей универсального C #.

Все дженерики просто шаблонизируют подпись.

Имя делегата выбрано неправильно (если только вы не думаете, что все наши приложения управляются фреймворками). Потому что использование не всегда "делегировать". Часто код, которому вы делегировали некоторую ответственность (скажем, итератор), вызывает «делегата», которого вы ранее отправили. Именно поэтому вы часто видите термин «обратный вызов».

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

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

0 голосов
/ 19 марта 2010

См. Ссылку для получения подробной информации о делегатах и ​​событиях DotNet: http://www.codeproject.com/KB/cs/Delegate_To_Event_in_CS.aspx

0 голосов
/ 19 марта 2010

Они, черт возьми, смущали меня, пока я не прочитал:

  1. Объяснения Эндрю Троелсена о них в Pro C # 2008 и платформе .Net 3.5
  2. Глава, посвященная шаблону Observer в Шаблоны Head First Design *

Эта вторая книга посвящена Java, и в ней не упоминаются делегаты, но в ней хорошо объясняется проблема, которую помогают решить делегаты:общение между классами.

0 голосов
/ 19 марта 2010

Вы бы передали ему метод void, который принимает IEnumerable и Exception в качестве параметров ...

Скажем, у вас есть этот метод:

public void DoSomeStuffWithCustomers(
  IEnumerable<Customer> customers, Exception exception)
{     
}

Вы бы вызвали метод GetCustomers следующим образом:

GetCustomers(DoSomeStuffWithCustomers);
...