2009-03-27 3 views
2

Почему IAsyncResult требует, чтобы я сохранил ссылку на делегата, который BeginInvoked?IAsyncResult

Я хотел бы быть в состоянии написать что-то вроде:

new GenericDelegate(DoSomething).BeginInvoke(DoSomethingComplete); 

void DoSomethingComplete(IAsyncResult ar) 
{ 
    ar.EndInvoke(); 
} 

ответ

2

Вам необязательно оставлять свои собственные ссылки на делегата при выполнении нормального делегат BeginInvoke; вы можете наложить IAsyncResult на номер AsyncResult и получить делегат от объекта AsyncDelegate. И прежде чем кто-нибудь скажет: «Это грязный хак», it's documented as being valid at MSDN.

Класс AsyncResult используется в сочетании с асинхронными вызовами метода, выполненными с использованием делегатов. IAsyncResult, возвращенный из метода BeginInvoke делегата, может быть перенесен в AsyncResult. AsyncResult имеет свойство AsyncDelegate, которое содержит объект делегирования, на который был вызван асинхронный вызов.

Таким образом, вы могли бы написать:

new GenericDelegate(DoSomething).BeginInvoke(DoSomethingComplete); 

void DoSomethingComplete(IAsyncResult ar) 
{ 
    ((GenericDelegate)((AsyncResult)ar).AsyncDelegate)).EndInvoke(); 
} 

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


Под «нормальным» здесь я имею в виду BeginInvoke на экземпляр делегата, используя метод сгенерированного компилятором. Эта технология кастинга до AsyncResult не гарантируется при использовании заранее определенных методов, то есть при использовании класса, который объявляет свои собственные методы BeginX/EndX. Это связано с тем, что класс может делать что-то более умное внутри, например, блокировать порты ввода IO и, следовательно, использовать другой тип IAsyncResult. Тем не менее, в сценарии, как положено, он будет работать нормально.

1

IAsyncResult очень ... перегружен интерфейс. Чтобы быть удобным интерфейсом во многих сценариях, он может действительно иметь только свойства и поля, которые применимы ко всем сценариям, в которых он используется. В противном случае API-интерфейсы будут пытаться предоставить параметры, которые просто не являются естественными для их конкретных потребностей.

В только подмножестве обстоятельств возникает создание IAsyncResult для делегата. Другие сценарии, такие как Control.BeginInvoke, не начинаются с делегата и не смогут передать их свойствам интерфейса, если они существуют.

IAsyncResult берет минималистский подход здесь и обладает только свойствами, которые могут использовать все его применения.

0

Попробуйте пропускание делегата в качестве параметра состояния асинхронного, таких как,

class Program { 
    static void Main(string[] args) { 
     Action d = delegate { 
      Console.WriteLine("From the delegate"); 
     }; 
     var e = new ManualResetEvent(false); 
     d.BeginInvoke(r => { 
      ((Action)r.AsyncState).EndInvoke(r); 
      e.Set(); 
     }, d); 
     e.WaitOne(); 
    } 
} 
+1

Упрощенный захват «d»: d.BeginInvoke (r => {d.EndInvoke (r); ...}, null); [согласно сообщению в блоге, указанному выше]. –

2

Я нахожу все Begin/End модель излишне сложной - так что я had a look at wrapping it up (очень сравним с тем, что использует F #). Результат: больше не нужно сохранять делегата (и т. Д.).

+0

+1 - Я не уверен, что это упрощает работу с нормальными делегатами (см. Мой ответ для чего), но мне нравится, что он работает с заранее определенными методами BeginX/EndX. Закрытие FTW! –