Two questions on the callback pattern with AsyncCallback and IAsyncResult.
I changed the question with a code example:
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);
}
BEGIN EDIT
I am beginning to see what is going on.
I have mixed up a WCF async pattern and a normal async pattern.
In WCF one uses a proxy and the Begin- and EndMethod must be passed the proxy and not the function delegate. In the WCF case the casting works, in the normal case not.
WCF uses the [OperationContract(AsyncPattern = true)] attribute probably to enforce a somewhat different pattern.
END EDIT
Why the error on the line return (string)(result.AsyncState);
?
Exactly the same pattern in production code is ok.
Secondly, why can I not debug code in BeginMethod of class Test?
I can only break in WorkerFunction.
Let me give you this sample code to make things a bit clear. Please create a new console app and use this
As you can see the callback function (MyCallBack) gets an IAsyncResult object passed back to it. It is this IAsynchResult object whose AyncState gives you the original object you had passed in the BeginInvoke method call. In this case (and as a general practice) you pass in the delegate itself as the object (which was the variable called "function"). One the callback was called, I then got the original delegate object back by quering the ar.AsyncState, I then called EndInvoke on it to get back the result.
As for the breakpoint not being hit, I am afraid I need some more information on it. What exactly do you mean? Where is this Console.WriteLine statement?
NEW RESPONSE OK here is my version of your code. Basically no matter where you call the EndInvoke from, you need to call it on the actual delegate object (in your case the "function" variable you instantiate, passing it the actual IAsyncResult object). The code you have is trying to mask this facility however I must say there are less complicated ways of doing this. I will be more than happy to write a wrapper of sorts for you if you wish. For now I am simply giving you your code back with my small addition in it, that should make it work. Since you are using class level variables hence I am forced to use one myself. This is not really thread safe at the moment. But here goes