Modifier: Déplacement de la question vers le haut.Comment est-ce que je peux éviter de passer/stocker un délégué en utilisant BeginInvoke et EndInvoke?
Mise à jour: Trouvé un exemple par Microsoft, niché sur un peu plus de code à la fin.
Mes questions sont les suivantes:
- Est-il sûr d'appeler plusieurs BeginInvoke fait appel à la même instance de délégué, ou dois-je construire une nouvelle instance de délégué pour chaque appel de méthode en vol?
- Si je dois construire de nouvelles instances pour chacun, existe-t-il un moyen d'obtenir le délégué original hors de la valeur IAsyncResult?
- Existe-t-il un autre moyen, mieux, d'ajouter un support asynchrone à ma classe que d'utiliser des délégués?
Plus d'informations ci-dessous.
Je suis en train d'ajouter un support asynchrone à une de mes classes, et j'ai pensé que je le ferais simplement.
Prenez cette classe:
public class Calculator
{
public Int32 Add(Int32 a, Int32 b)
{
return a + b;
}
}
Je pensais que je pourrais simplement faire ceci:
public class Calculator
{
private delegate Int32 AddDelegate(Int32 a, Int32 b);
public Int32 Add(Int32 a, Int32 b)
{
return a + b;
}
public IAsyncResult BeginAdd(Int32 a, Int32 b,
AsyncCallback callback, Object obj)
{
return new AddDelegate(Add).BeginInvoke(a, b, callback, obj);
}
public Int32 EndAdd(IAsyncResult ar)
{
return new AddDelegate(Add).EndInvoke(ar);
}
}
Cela ne fonctionne pas, comme les deux méthodes chacun construit son propre objet délégué, et. L'appel EndInvoke vérifie si l'instance de délégué sur laquelle je l'appelle est la même que celle que j'ai appelée BeginInvoke.
La façon la plus simple de gérer ce serait juste stocker une référence dans une variable, comme ceci:
public class Calculator
{
private delegate Int32 AddDelegate(Int32 a, Int32 b);
private AddDelegate _Add;
public Calculator()
{
_Add = new AddDelegate(Add);
}
public Int32 Add(Int32 a, Int32 b)
{
return a + b;
}
public IAsyncResult BeginAdd(Int32 a, Int32 b,
AsyncCallback callback, Object obj)
{
return _Add.BeginInvoke(a, b, callback, obj);
}
public Int32 EndAdd(IAsyncResult ar)
{
return _Add.EndInvoke(ar);
}
}
Notez que je suis pleinement conscient des problèmes permettant de multiples méthodes d'instance sur la même classe à exécuter en même temps, en ce qui concerne l'état partagé, etc.
Mise à jour: Je trouve cet exemple ici par Microsoft sur Asynchronous Delegates Programming Sample. Il montre le renvoi de la référence IAsyncResult à un objet AsyncResult, puis je peux obtenir l'instance de délégué d'origine via la propriété AsyncDelegate.
Est-ce une approche sécuritaire?
En d'autres termes, la classe suivante est-elle correcte?
public class Calculator
{
private delegate Int32 AddDelegate(Int32 a, Int32 b);
public Int32 Add(Int32 a, Int32 b)
{
return a + b;
}
public IAsyncResult BeginAdd(Int32 a, Int32 b, AsyncCallback callback, Object obj)
{
return new AddDelegate(Add).BeginInvoke(a, b, callback, obj);
}
public Int32 EndAdd(IAsyncResult ar)
{
AddDelegate del = (AddDelegate)((AsyncResult)ar).AsyncDelegate;
return del.EndInvoke(ar);
}
}
J'ai besoin des valeurs retournées, donc IAsyncResult et le soutien des délégués a l'air tache sur mes besoins, mais je Regarde ton code. Notez que les deux méthodes RunAsync statiques que vous avez définies ici ont la même liste de paramètres, donc elles ne seront pas compilées. –
Ok, j'imagine que j'ai trouvé ce casting via AsyncResult pendant que vous écriviez. Donc, c'est sûr de le faire? Il ne va pas y avoir une situation avec des délégués comme ceci où l'objet retourné n'est * pas * un objet AsyncResult? (notez que je ne pose pas de questions sur IAsyncResult dans le cas général, juste de delegate.BeginInvoke.) –
Voir ma réponse pour une méthode qui ne dépend pas d'une implémentation spécifique de IAsyncResult – thecoop