Inisde the callback after BeginInvoke, AsyncResult.AsyncDelegate needs to be cast to proper type, only then EndInvoke is accessible.
But I am using generics, so do I need to define N callbacks for N generalized methods?
This is the class:
public class Async
{
public delegate object Func(); //void with no parameter
public delegate TResult Func<T, TResult>(T arg); //one parameter with result
public static void Execute(IAsyncSubscriber subscriber, Func action)
{
action.BeginInvoke(Callback, subscriber);
}
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback, subscriber);
}
private static void Callback(IAsyncResult ar)
{
AsyncResult result = (AsyncResult)ar;
IAsyncSubscriber subscriber = (IAsyncSubscriber)result.AsyncState;
Func action = (Func) result.AsyncDelegate;
object returnValue = action.EndInvoke(result); //To call endinvoke
subscriber.Callback(returnValue);
}
}
There are a few ways in which you can avoid defining N callbacks:
You can pass the corresponding EndInvoke method as state in the BeginInvoke call. e.g.
private delegate T EndInvokeDelegate<T>(IAsyncResult ar);
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback<T1>, new object[]{subscriber, new new EndInvokeDelegate<T1>(action.EndInvoke)});
}
public static void Execute<T, T1, T2>(IAsyncSubscriber subscriber, T param1, T1 param2, Func<T, T1, T2> action)
{
action.BeginInvoke(param1, param2, Callback<T2>, new object[]{subscriber, new new EndInvokeDelegate<T2>(action.EndInvoke)});
}
private static void Callback<TR>(IAsyncResult ar)
{
object[] stateArr = (object[])ar.AsyncState;
IAsyncSubscriber subscriber = (IAsyncSubscriber)stateArr[0];
EndInvokeDelegate<TR> action = (EndInvokeDelegate<TR>)stateArray[1];
TR returnValue = action(ar);
subscriber.Callback(returnValue);
}
You can also make Callback non-generic by treating stateArray[1] as MultiCastDelegate and using DynamicInvoke on it but that would be slow.
For .Net 2.0 and 3.0, you can use reflection e.g.
Type actionType= result.AsyncDelegate.GetType();
var minfo = actionType.GetMethod("EndInvoke");
object returnValue = minfo.Invoke(res.AsyncDelegate, new object[] { ar });
For .Net 4.0, you can use dynamic. e.g.
dynamic action = result.AsyncDelegate;
object returnValue = action.EndInvoke(result);
If I understand correctly, your assumption is correct. You will need to define N callbacks.
On the bright side, you will only be doing this once, so no biggy, just a little repetitive work :)
Related
Consider the following pseudo code:
TResult Foo<TResult>(Func<T1, T2,...,Tn, TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
The function accepts Func<> with unknown number of generic parameters and a list of the corresponding arguments. Is it possible to write it in C#? How to define and call Foo? How do I pass args to f?
You can use Delegate with DynamicInvoke.
With that, you don't need to handle with object[] in f.
TResult Foo<TResult>(Delegate f, params object[] args)
{
var result = f.DynamicInvoke(args);
return (TResult)Convert.ChangeType(result, typeof(TResult));
}
Usage:
Func<string, int, bool, bool> f = (name, age, active) =>
{
if (name == "Jon" && age == 40 && active)
{
return true;
}
return false;
};
Foo<bool>(f,"Jon", 40, true);
I created a fiddle showing some examples: https://dotnetfiddle.net/LdmOqo
Note:
If you want to use a method group, you need to use an explict casting to Func:
public static bool Method(string name, int age)
{
...
}
var method = (Func<string, int, bool>)Method;
Foo<bool>(method, "Jon", 40);
Fiddle: https://dotnetfiddle.net/3ZPLsY
That's not possible. At best, you could have a delegate that also takes a variable number of arguments, and then have the delegate parse the arguments
TResult Foo<TResult>(Func<object[], TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
Foo<int>(args =>
{
var name = args[0] as string;
var age = (int) args[1];
//...
return age;
}, arg1, arg2, arg3);
This could become easy with lambda expressions:
TResult Foo<TResult>(Func<TResult> f)
{
return f();
}
Then usage could be like:
var result = Foo<int>(() => method(arg1, arg2, arg3));
Where method can be arbitrary method returning int.
This way you can pass any number of any erguments directly through lambda.
To support asynchoronous code we can define:
Task<TResult> Foo<TResult>(Func<Task<TResult>> f)
{
return f();
}
// or with cancellation token
Task<TResult> Foo<TResult>(Func<CancellationToken, Task<TResult>> f, CancellationToken cancellationToken)
{
return f(cancellationToken);
}
and use it like:
var asyncResult = await Foo(async () => await asyncMethod(arg1, arg2, arg3));
// With cancellation token
var asyncResult = await Foo(
async (ct) => await asyncMethod(arg1, arg2, arg3, ct),
cancellationToken);
You could try something similar to what I posted here: https://stackoverflow.com/a/47556051/4681344
It will allow for any number of arguments, and enforces their types.
public delegate T ParamsAction<T>(params object[] args);
TResult Foo<TResult>(ParamsAction<TResult> f)
{
TResult result = f();
return result;
}
to call it, simply......
Foo(args => MethodToCallback("Bar", 123));
In some cases you may be able to get away with a trick like this:
public static class MyClass
{
private static T CommonWorkMethod<T>(Func<T> wishMultipleArgsFunc)
{
// ... do common preparation
T returnValue = wishMultipleArgsFunc();
// ... do common cleanup
return returnValue;
}
public static int DoCommonWorkNoParams() => CommonWorkMethod<int>(ProduceIntWithNoParams);
public static long DoCommonWorkWithLong(long p1) => CommonWorkMethod<long>(() => ProcessOneLong(p1));
public static string DoCommonWorkWith2Params(int p1, long p2) => CommonWorkMethod<string>(() => ConvertToCollatedString(p1, p2));
private static int ProduceIntWithNoParams() { return 5; }
}
Although it is not really what asked, a simple workaround would be to define several Foo method with different number of type arguments.
It is uncommon to have function with more than 6 parameters, so one could define the following method and get away with almost every use case, while staying type safe. Renan's solution could then be used for the remaining cases.
public TResult Foo<TResult> (Func<TResult> f)
{
return f();
}
public TResult Foo<T1, TResult>(Func<T1, TResult> f, T1 t1)
{
return f(t1);
}
public TResult Foo<T1, T2, TResult>(Func<T1, T2, TResult> f, T1 t1, T2 t2)
{
return f(t1, t2);
}
...
Maybe simple question but how can I get the return object of a asynchronously System.Func?
Consider this:
private void Start(String a)
{
System.Func<String, objectA> callasync = delegate(String strA)
{
return bla(stra); // Which return a objectA
}
callasync.BeginInvoke(a, callback, null);
}
private void callback(IAsyncResult ar)
{
// Here I want the objectA but how ??
}
With callback function, I didn't have the delegate signature. And of course, i can create a delegate in scope of the class but maybe is there a solution to read the return value in the callback function.
Thank.
When you use BeginInvoke on a delegate, the IAsyncResult of passed to the callback will be an instance of the AsyncResult class. From that you can get an instance of your delegate and call EndInvoke on it.
private void Start(string a)
{
Func<string, objectA> d = strA => bla(strA);
d.BeginInvoke(a, Callback, null);
}
private void Callback(IAsyncResult ar)
{
AsyncResult asyncResult = (AsyncResult)ar;
Func<string, objectA> d = (Func<string, objectA>)asyncResult.AsyncDelegate;
objectA result = d.EndInvoke(ar);
}
You could also do something like this (not written in IDE, may contain errors)
private Func<String, objectA> _callDoWorkAsync = DoWork;
private static string DoWork( objectA strA )
{
return bla( strA );
}
private void Start( String a )
{
_callDoWorkAsync.BeginInvoke( a, callback, null );
}
private void callback( IAsyncResult ar )
{
objectA strA = (objectA) _callDoWorkAsync.EndInvoke( ar );
}
I have several methods all returning void with different signature (parameters) and different names. I need to pass those methods as a parameter in a generic method that will invoke it latter. Also that need to be as transparent as possible.
Following what I got so far:
private void button1_Click(object sender, EventArgs e)
{
Action<string,int> TestHandler = Test;
InvokeMyMethod(TestHandler);
Action<string, int,object > TestHandlerN = TestN;
InvokeMyMethod(TestHandlerN);
}
public void InvokeMyMethod(Delegate Method)
{
object[] args = new object[X];
Method.DynamicInvoke();
}
public void Test(string t1, int t2)
{
MessageBox.Show(t1 + t2);
}
public void TestN(string t1, int t2, object t3)
{
MessageBox.Show(t1 + t2);
}
That is what I need:
private void button1_Click(object sender, EventArgs e)
{
InvokeMyMethod(Test);
InvokeMyMethod(TestN);
}
public void InvokeMyMethod(XXX_Type Method)
{
object[] args = new object[X];
Method.DynamicInvoke(args);
}
public void Test(string t1, int t2)
{
MessageBox.Show(t1 + t2);
}
public void TestN(string t1, int t2, object t3)
{
MessageBox.Show(t1 + t2);
}
This doesn't answer your question directly, but here is how I solve a similar problem:
public static partial class Lambda
{
public static Action Pin<T0>
(
this Action<T0> action,
T0 arg0
)
{
return () => action(arg0);
}
public static Func<TResult> Pin<T0, TResult>
(
this Func<T0, TResult> func,
T0 arg0
)
{
return () => func(arg0);
}
public static Action Pin<T0, T1>
(
this Action<T0, T1> action,
T0 arg0,
T1 arg1
)
{
return () => action(arg0, arg1);
}
public static Func<TResult> Pin<T0, T1, TResult>
(
this Func<T0, T1, TResult> func,
T0 arg0,
T1 arg1
)
{
return () => func(arg0, arg1);
}
// More signatures omitted for brevity...
// I would love it if C# supported variadic template parameters :-)
}
The idea is that if you have an Action which requires arguments, you can say:
Action<int, string> foo;
Action a = foo.Pin(5, "bleh");
Have the code generator.
Likewise, you might want to have a way to curry to some other delegate type (like Action<string, int>). The difference between my method and yours is that mine is not late-bound, but you do not appear to be using late-binding anyway, so early-binding gives you some compile-time type safety.
I'm not sure you can do what I think you are asking. You call method.DynamicInvoke with some object[], but how did you get values for those parameters?
And to answer the question before anybody asks it, I created the Lambda.Pin functions because I was tired of making this mistake:
Action<int> foo;
foreach (int i in someList)
AddAction(() => foo(i));
public void InvokeMyMethod(Delegate method) {
Method.DynamicInvoke(new object[] {"Test", 1});
}
But you need to invoke it like
InvokeMyMethod((Action<string, int>)Test);
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
public class Test
{
private int WorkerFunction(string a, string b)
{
//this is the guy that is supposed to do the long running work
Console.WriteLine(a);
Console.WriteLine(b);
return a.Length + b.Length;
}
private void MyCallBack(IAsyncResult ar)
{
Func<string, string, int> function = ar.AsyncState as Func<string, string, int>;
int result = function.EndInvoke(ar);
Console.WriteLine("Result is {0}", result);
}
public void CallMethod()
{
Func<string, string, int> function = new Func<string, string, int>(WorkerFunction);
IAsyncResult result = function.BeginInvoke("param1", "param2", MyCallBack, function);
}
}
class Program
{
static void Main(string[] args)
{
Test test = new Test();
test.CallMethod();
}
}
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
using System;
using System.Collections.Generic;
using System.Text;
namespace TestAsync
{
class Program
{
private static Wrapper test = new Wrapper();
static void Main(string[] args)
{
var objectState = new object();
test.BeginMethod("parameter 1", "parameter 2", Callback, objectState);
Console.ReadKey();
}
private static void Callback(IAsyncResult ar)
{
string result = test.EndMethod(ar);
Console.WriteLine(result);
}
}
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
{
Func<string, string, string> _delgateObject;
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);
this._delgateObject = function;
IAsyncResult result = function.BeginInvoke(s1, s2, cb, state);
return result;
}
public string EndMethod(IAsyncResult result)
{
var test = result.AsyncState;
return this._delgateObject.EndInvoke(result);
}
}
public delegate TResult Func<T1, T2, TResult>(T1 t1, T2 t2);
}
This article helped me understand what was going on. Wcf's OperationContract implements a special Async pattern, that synchronously calls [Operation] on a seperate thread. Begin[Operation] and End[Operation] are used to create the pattern but they will not really be invoked. So this pattern with its signatures and attributes seems to be identical with makeing a synchronous call on the client via e.g. a BackgroundWorker.
You can only set AsyncPattern [of OperationContract attribute] to true on a method with a BeginOperation-compatible signature, and the defining contract must also have a matching method with an EndOperation-compatible signature. These requirements are verified at the proxy load time. What AsyncPattern does is bind the underlying synchronous method with the Begin/End pair, and correlates the synchronous execution with the asynchronous one. Briefly, when the client invokes a method of the form BeginOperation with AsyncPattern set to true, it tells WCF not to try to directly invoke a method by that name on the service. Instead, it will use a thread from the thread pool to synchronously call the underlying method (identified by the Action name). The synchronous call will block the thread from the thread pool, not the calling client. The client will only be blocked for the slightest moment it takes to dispatch the call request to the thread pool. The reply method of the synchronous invocation is correlated with the EndOperation method.
I am consuming a web service which has a number of methods (50) which create different objects.
example:
CreateObject1(Object1 obj, int arg2)
CreateObject2(Object2 obj, int arg2)
...
CreateObjectX(ObjectX obj, int arg2)
All Objects (Object1, Object2, ObjectX...) inherit from ObjectBase.
So I am trying to do this...
delegate void DlgtCreateObject(ObjectBase obj, int arg2);
public void CreateObject(ObjectBase obj, int arg2)
{
DlgtCreateObject dlgt;
string objType;
string operation;
objType = obj.GetType().ToString();
operation = "Create" + objType.Substring(objType.LastIndexOf(".") + 1);
using (MyWebService service = new MyWebService())
{
dlgt = (DlgtCreateObject)Delegate.CreateDelegate(typeof(DlgtCreateObject),
service,
operation,
false,
true);
dlgt(obj, arg2);
}
}
Unfortunately this gives me a Failed to Bind exception.
I believe this is because my delegate signature uses the ObjectBase as its first argument where the functions use the specific classes.
Is there a way around this?
If you're only trying to call the methods within here, I suggest you use Type.GetMethod and MethodBase.Invoke instead of going via delegates. Then you won't run into this problem.
Right after posting I figured generics might be the answer, and indeed the following seems to do the trick...
delegate void DlgtCreateObject<T>(T obj, int arg2) where T : ObjectBase;
public void CreateObject<T>(T obj, int arg2) where T : ObjectBase;
{
DlgtCreateObject dlgt;
string objType;
string operation;
objType = obj.GetType().ToString();
operation = "Create" + objType.Substring(objType.LastIndexOf(".") + 1);
using (MyWebService service = new MyWebService())
{
dlgt = (DlgtCreateObject<T>)Delegate.CreateDelegate(typeof(DlgtCreateObject<T>),
service,
operation,
false,
true);
dlgt(obj, arg2);
}
}