Deux questions à propos de AsyncCallback et modèle IAsyncResult
Deux questions sur le rappel du motif avec AsyncCallback et IAsyncResult.
J'ai changé la question avec un exemple de code:
using System;
using System.Collections.Generic;
using System.Text;
namespace TestAsync
{
class Program
{
private static Wrapper test = new Wrapper();
static void Main(string[] args)
{
test.BeginMethod("parameter 1", "parameter 2", Callback);
Console.ReadKey();
}
private static void Callback(IAsyncResult ar)
{
string result = test.EndMethod(ar);
}
}
public interface ITest
{
IAsyncResult BeginMethod(string s1, string s2, AsyncCallback cb, object state);
string EndMethod(IAsyncResult result);
}
public class Wrapper
{
private ITest proxy = new Test();
public void BeginMethod(string s1, string s2, AsyncCallback cb)
{
proxy.BeginMethod(s1, s2, cb, proxy);
}
public string EndMethod(IAsyncResult result)
{
return ((ITest)(result.AsyncState)).EndMethod(result);
}
}
public class Test : ITest
{
private string WorkerFunction(string a, string b)
{
//"long running work"
return a + "|" + b;
}
public IAsyncResult BeginMethod(string s1, string s2, AsyncCallback cb, object state)
{
Func<string, string, string> function = new Func<string, string, string>(WorkerFunction);
IAsyncResult result = function.BeginInvoke(s1, s2, cb, state);
return result;
}
public string EndMethod(IAsyncResult result)
{
return (string)(result.AsyncState);
}
}
public delegate TResult Func<T1, T2, TResult>(T1 t1, T2 t2);
}
COMMENCER À MODIFIER
Je commence à voir ce qui se passe.
J'ai mélangé un WCF async modèle et de normal async modèle.
Dans WCF on utilise un serveur proxy et le Commencer - et cette instruction se doit être passé le proxy et non pas la fonction de délégué. Dans la WCF cas, le casting fonctionne, dans le cas normal, pas.
WCF utilise le [OperationContract(AsyncPattern = true)] attribut probablement à appliquer un peu de modèle différent.
FIN MODIFIER
Pourquoi l'erreur sur la ligne return (string)(result.AsyncState);
?
Exactement le même modèle dans le code de production est ok.
Deuxièmement, pourquoi je ne peux pas le code de débogage dans BeginMethod de la classe de Test?
Je ne peux pause dans WorkerFunction.
OriginalL'auteur Gerard | 2011-02-23
Vous devez vous connecter pour publier un commentaire.
Permettez-moi de vous donner cet exemple de code pour rendre les choses un peu. Veuillez créer une nouvelle application console et utiliser ce
Comme vous pouvez le voir, la fonction de rappel (MyCallBack) obtient un objet IAsyncResult passé. C'est ce IAsynchResult objet dont AyncState vous donne l'objet d'origine tu avais passé dans la méthode BeginInvoke appel. Dans ce cas, (et en général) vous pouvez passer le délégué lui-même comme l'objet (qui est la variable appelée "fonction").
Un rappel a été appelé, je puis a obtenu le délégué d'origine de l'objet en arrière par quering l'ei.AsyncState, j'ai alors appelé EndInvoke sur elle pour obtenir le résultat en retour.
Comme pour le point d'arrêt ne pas être frappé, j'ai peur, j'ai besoin de plus d'informations sur elle. Que voulez-vous dire exactement? Où est cette Console.WriteLine déclaration?
NOUVELLE RÉPONSE
OK, voici ma version de votre code. Fondamentalement, n'importe où vous appelez la EndInvoke, vous devez appeler le délégué de l'objet (dans votre cas, la "fonction" de la variable à instancier, en lui passant le réel objet IAsyncResult). Le code que vous avez est d'essayer de masquer cette installation mais je dois dire qu'il y a de moins en moins compliqué façons de le faire. Je serai plus qu'heureux d'écrire un wrapper de toutes sortes pour vous si vous le souhaitez. Pour l'instant, je suis simplement en vous donnant votre code de retour avec mon petit plus, qui devrait le faire fonctionner. Puisque vous utilisez le niveau de la classe de variables donc je suis obligé d'utiliser un moi-même. Ce n'est pas vraiment thread-safe pour le moment. Mais voilà
object @object
paramètre d'état - savez-vous si c'est obligatoire?Au lieu de
IAsyncResult result = function.BeginInvoke(...
pourrais-tu juste fairefunction.BeginInvoke(...
?Oui désolé que la fonction de Rappel doit être WorkerFunction. Je vais changer cela maintenant. Il n'est pas obligatoire de remplir la fonction de délégué comme l' @l'état de l'objet en paramètre. Cependant comme vous pouvez le voir faire qui vous donne accès au délégué à l'intérieur de la fonction de Rappel du corps. Vous avez besoin de faire appel à un EndInvoke sur le délégué de l'intérieur de la fonction de rappel si vous avez besoin de la fonction de délégué de référence. Et oui, vous pouvez tout simplement le faire fonctionner.BeginInvoke. J'ai gardé l'échantillon à la même syntaxe que vous utilisez vraiment. Comme vous pouvez le voir, je ne les réutilisez pas le "résultat" de la variable après le BeginInvoke
IMO il est écrit de manière un peu plus compliqué de style alors qu'il est censé être. Je peux voir où votre problème. Donnez-moi quelques minutes et je vais le corriger pour vous.
+1 C'est un très bon exemple!
OriginalL'auteur Nikhil
Cet article m'a aidé à comprendre ce qui se passait. La Wcf
OperationContract
met en œuvre un spécial Async motif, que de façon synchrone appels [Fonctionnement] sur un sujet séparé. Commencer[de l'Opération] et à la Fin[de l'Opération] sont utilisés pour créer le motif, mais ils ne seront pas vraiment être invoquée. Donc, ce modèle avec ses signatures et les attributs semble être identique avec la grâce d'un appel synchrone sur le client, par exemple, à un BackgroundWorker.Vous pouvez uniquement définir AsyncPattern [de
OperationContract
attribut] à true sur une méthode avec un BeginOperation-compatible signature, et la définition de contrat doit également disposer d'une méthode d'appariement avec un EndOperation-compatible signature. Ces exigences sont vérifiées par le proxy du temps de chargement. Ce AsyncPattern n'est lier le sous-jacent méthode synchrone avec les mots Begin et End, et les corrélats de l'exécution synchrone avec l'asynchrone. En bref, quand le client appelle une méthode de la forme BeginOperation avec AsyncPattern défini sur true, il dit WCF de ne pas essayer d'invoquer directement une méthode de ce nom sur le service. Au lieu de cela, il va utiliser un fil de la piscine de façon synchrone appeler le sous-jacent de la méthode (identifié par le nom de l'Action). L'appel synchrone va bloquer le fil de la piscine, pas le client appelant. Le client ne peut être bloqué pour le moindre moment il faut envoyer la demande d'appel au pool de threads. La méthode de réponse de l'invocation synchrone est en corrélation avec la EndOperation méthode.OriginalL'auteur Gerard