Объясните делегатов.NET

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

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

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

11
задан Michael Petrotta 19 March 2010 в 01:35
поделиться

9 ответов

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

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

GetCustomers(SendExceptionToCustomers);

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

EDIT в ответ на комментарий


Хорошо, имеет смысл, так что теперь зачем вообще беспокоиться с функцией 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
})


Также Slak's комментарий предлагает другую причину для параметра делегата - GetCustomers действительно извлекает клиентов, но асинхронно. Всякий раз, когда он завершает получение клиентов, он вызывает функцию, которую вы даете ему, либо со списком клиентов, либо с исключением, если произошло исключение.
9
ответ дан 3 December 2019 в 06:46
поделиться

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

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

Все дженерики - это просто шаблон подписи.

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

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

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

1
ответ дан 3 December 2019 в 06:46
поделиться

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

Допустим, у вас есть этот метод:

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

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

GetCustomers(DoSomeStuffWithCustomers);
0
ответ дан 3 December 2019 в 06:46
поделиться

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

0
ответ дан 3 December 2019 в 06:46
поделиться

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

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

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

0
ответ дан 3 December 2019 в 06:46
поделиться

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

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

Вторая функция должна принимать два параметра типа IEnumerable и 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);
3
ответ дан 3 December 2019 в 06:46
поделиться

вы можете вызвать его с помощью лямбда

GetCustomers((cust, ex) => {
    //do something here}
);
2
ответ дан 3 December 2019 в 06:46
поделиться

Просто? Указатели функций

1
ответ дан 3 December 2019 в 06:46
поделиться
Другие вопросы по тегам:

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