#c# #.net #begininvoke #multicastdelegate
#c# #.net #begininvoke #многоадресная передача
Вопрос:
Согласно Джону Скиту, «Вы можете вызвать BeginInvoke только для делегата, у которого есть единственный целевой вызов».
Почему это? В чем настоящая причина?
Примечание: Для пояснения (и потому что я допустил эту ошибку), я говорю о BeginInvoke
о делегатах, а не об элементах управления.
Комментарии:
1. Если вы вызываете делегат синхронно, он каким-то образом знает, какой из них запускать первым, почему асинхронное выполнение должно отличаться?
2. @svick: Я думаю, этого не было бы. Он вызывает в порядке их добавления, правильно?
3. @svick: Я убрал свое «предположение» из своего вопроса. Я действительно не знаю, почему вы не можете
BeginInvoke
наMulticastDelegate
.
Ответ №1:
Я думаю, Джон Скит хорошо объясняет в сообщении, на которое вы ссылаетесь:
Как вы хотите, чтобы обработка потоков работала? Обязательно ли запускать каждый вызов синхронно, но выполнять все это асинхронно по отношению к вызывающему потоку, или вы могли бы запускать каждый вызов асинхронно?
Если это первое, просто запустите один рабочий элемент threadpool, который синхронно вызывает делегат. Если это последнее, получите список вызовов с делегированием.Получите Invocationlist и вызовите BeginInvoke для элемента списка по очереди.
В принципе, вызов BeginInvoke
для MulticastDelegate
неоднозначен, вы хотите, чтобы делегаты ждали друг друга или нет? Хотя теоретически это могло бы решиться за вас, был сделан выбор, чтобы заставить вас явно выбрать нужный вам метод, вызвав делегатов другим способом.
Другими словами, это выбор дизайна, позволяющий избежать путаницы. Также важно отметить, что BeginInvoke
это вышло из моды, и доступны более новые методы асинхронного программирования, что делает обновление этого старого стандарта маловероятным, поэтому, даже если бы они захотели изменить сейчас, нет причин для этого.
Ответ №2:
Учитывая любой тип делегата, можно довольно легко написать класс, который будет объединять делегаты либо этого типа, либо производного типа и выдавать объединенный делегат, который будет делать практически все, что может делать MulticastDelegate
, и ряд вещей, которые он не может. Единственное, что стиль объединенного делегата не смог бы сделать, это удалить его подкомпоненты с помощью Delegate.Remove
(поскольку эта функция просто рассматривала бы объединенный делегат как единое целое). В отличие от MulticastDelegate, объединенный делегат мог бы включать производные типы делегатов и отлично работал бы в местах, которым нужен только один целевой объект.
В vb.net код был бы чем-то вроде:
Класс Double Action(из T) Частные _Act1, _Act2 как действие (из T) Новый частный подраздел (обычно Act1 как действие (из T), обычно Act2 как действие (из T)) _Act1 = Act1 _Act2 = Act2 Завершить подзаголовок Частный вспомогательный вызов (обычно используется как T) _Act1(параметр) _Act2(параметр) Завершить подзаголовок Функция комбинирует (обычно Act1 как действие (из T), обычно Act2 как действие (из T)) Как действие (из T) Отключить newAct как новое двойное действие (из T) (Act1, Act2) Возвращает адрес нового действия.Вызвать Завершить функцию Завершить класс
Перевод на C # должен быть простым.
Единственная реальная проблема с этим подходом к объединению делегатов заключается в том, что для поддержки каждого универсального семейства делегатов требуется шаблонный код (поскольку .net не позволяет использовать делегатов в качестве параметров универсального типа).
Ответ №3:
Существует также обходной путь для вызова метода BeginInvoke в системе.Объект MulticastDelegate:
public class Program{
public delegate void SayHello();
public void SayHelloAndWait(){
Console.WriteLine("HELLO..");
System.Threading.Thread.Sleep(5000);
Console.WriteLine("..WORLD!");
}
public void SayHi(){
Console.WriteLine("Hi world!");
}
public void Run(){
SayHello helloMethods;
helloMethods = SayHelloAndWait;
helloMethods = SayHi;
foreach(SayHello hello in helloMethods.GetInvocationList())
hello.BeginInvoke(null,null);
}
public static void Main(String[] args){
new Program().Run();
Console.Read();
}
}
Асинхронные методы вызываются последовательно от первого до последнего в зависимости от списка вызовов.