Вызвать BeginInvoke на MulticastDelegate? - PullRequest
9 голосов
/ 07 июня 2011

Согласно Джону Скиту , «Вы можете вызывать BeginInvoke только для делегата, у которого один целевой вызов.»

Почему это так?Какова реальная причина?

Примечание: Для пояснения (и потому что я допустил эту ошибку) я говорю о BeginInvoke для делегатов, а не для элементов управления.

Ответы [ 3 ]

7 голосов
/ 07 июня 2011

Я думаю, что Джон Скит хорошо справляется с объяснением в посте, который вы связали:

Как вы хотите, чтобы поток работал?Вам нужно выполнять каждый вызов синхронно, но выполнять все это асинхронно по отношению к вызывающему потоку, или вы могли бы запускать каждый вызов асинхронно?

Если это первый, просто запустите один рабочий элемент пула потоков, который вызываетделегат синхронно.Если это последнее, получите список вызовов с Delegate.GetInvocationList и вызовите BeginInvoke для элемента списка по очереди.

По сути, вызов BeginInvoke для MulticastDelegate является неоднозначным, хотите ли вы, чтобыделегатов ждать друг друга или нет?Хотя теоретически это могло бы решить для вас, был сделан выбор, чтобы заставить вас явно выбрать нужный метод, вызывая делегатов другим способом.

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

0 голосов
/ 27 июля 2017

Существует также обходной путь для вызова метода BeginInvoke для объекта System.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();
   }

}

Асинхронные методы вызываются последовательно от первого до последнего в зависимости от списка вызовов.

0 голосов
/ 27 мая 2012

При любом типе делегата можно довольно легко написать класс, который будет объединять делегаты, принадлежащие либо к этому типу, либо к производному типу, и получит комбинированный делегат, который будет делать практически все, что может сделать MulticastDelegate, и число.вещей, которые он не может.Единственное, что не смог бы сделать стиль объединенного делегата, - это удалить его подкомпоненты Delegate.Remove (поскольку эта функция будет рассматривать объединенный делегат как единое целое).В отличие от MulticastDelegate, объединенный делегат сможет включать производные типы делегатов и будет отлично работать в местах, где требуется только одна цель.

В vb.net код будет выглядеть примерно так:

Class DoubleAction(Of T)
    Private _Act1, _Act2 As Action(Of T)
    Private Sub New(ByVal Act1 As Action(Of T), ByVal Act2 As Action(Of T))
        _Act1 = Act1
        _Act2 = Act2
    End Sub
    Private Sub Invoke(ByVal Param As T)
        _Act1(Param)
        _Act2(Param)
    End Sub
    Function Combine(ByVal Act1 As Action(Of T), ByVal Act2 As Action(Of T)) As Action(Of T)
        Dim newAct As New DoubleAction(Of T)(Act1, Act2)
        Return AddressOf newAct.Invoke
    End Function
End Class

Перевод на C # должен быть простым.

Единственная реальная проблема с этим подходом для объединения делегатов состоит в том, что шаблонный код требуется для поддержки каждого общего семейства делегатов (так как .net не позволяетделегаты для использования в качестве параметров универсального типа).

...