2009-03-27 5 views
2

Pourquoi IAsyncResult nécessite-t-il de conserver une référence au délégué BeginInvoked?IAsyncResult

Je voudrais pouvoir écrire quelque chose comme:

new GenericDelegate(DoSomething).BeginInvoke(DoSomethingComplete); 

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

Répondre

2

Vous n'avez pas besoin de conserver votre propre référence à un délégué lorsque vous effectuez un travail normal délégué BeginInvoke; vous pouvez convertir le IAsyncResult en AsyncResult et récupérer le délégué de la propriété AsyncDelegate. Et avant que quelqu'un ne dise "c'est un bidouille", it's documented as being valid at MSDN.

La classe AsyncResult est utilisée conjointement avec les appels de méthode asynchrones effectués à l'aide de délégués. Le IAsyncResult renvoyé à partir de la méthode BeginInvoke du délégué peut être converti en un AsyncResult. AsyncResult possède la propriété AsyncDelegate qui contient l'objet délégué sur lequel l'appel asynchrone a été appelé.

Vous pouvez écrire:

new GenericDelegate(DoSomething).BeginInvoke(DoSomethingComplete); 

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

Notez que vous n'avez toujours de connaître le de type du délégué d'origine (ou du moins, je ne l'ai pas trouvé un moyen de contourner cette limitation; alors encore je n'ai pas essayé).


Par "normal" ici, je veux dire un BeginInvoke sur une instance de délégué, en utilisant la méthode généré par le compilateur. Cette technique de moulage à AsyncResult n'est pas garantie de fonctionner lors de l'utilisation de méthodes prédéfinies, c'est-à-dire lors de l'utilisation d'une classe qui déclare ses propres méthodes BeginX/EndX. C'est parce que la classe peut faire quelque chose de plus intelligent en interne comme bloquer sur les ports d'achèvement d'E/S, et peut donc utiliser un type différent de IAsyncResult. Cependant, dans le scénario tel que posé, cela fonctionnera très bien.

1

IAsyncResult est très ... Interface galvaudé. Pour être une interface utilisable dans de nombreux scénarios, il ne peut vraiment avoir les propriétés et les champs qui sont applicables à tous les scénarios dans lesquels il est utilisé. Autrement, les API auraient du mal à fournir des paramètres qui n'étaient tout simplement pas adaptés à leurs besoins spécifiques.

Dans un seul sous-ensemble des circonstances est la création d'un IAsyncResult se produire pour un délégué. D'autres scénarios tels que Control.BeginInvoke ne commencent pas par un délégué et ne peuvent pas en fournir un aux propriétés de l'interface si elles existaient.

IAsyncResult adopte l'approche minimaliste ici et ne possède que les propriétés que toutes ses utilisations peuvent fournir.

0

Essayez de passer le délégué comme paramètre d'état async tels que,

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

Plus simple pour capturer "d": d.BeginInvoke (r => {d.EndInvoke (r); ...}, null); [selon l'article de blog lié ci-dessus]. –

2

Je trouve l'ensemble Début/motif de fin inutilement complexe - donc je had a look at wrapping it up (très comparable à ce que F # utilise). Résultat: plus besoin de garder le délégué (etc).

+0

+1 - Je ne suis pas sûr que cela simplifie autant le travail avec les délégués normaux (voir ma réponse pour pourquoi) mais j'aime aussi que cela fonctionne aussi avec des méthodes prédéfinies de BeginX/EndX. Fermetures FTW! –

Questions connexes