c# 在回调中调用 endinvoke,使用泛型
Posted
技术标签:
【中文标题】c# 在回调中调用 endinvoke,使用泛型【英文标题】:c# calling endinvoke in callback, using generics 【发布时间】:2012-07-09 10:12:12 【问题描述】:BeginInvoke
之后的回调,AsyncResult.AsyncDelegate
需要转换为正确的类型,只有这样EndInvoke
才可以访问。
但是我使用的是泛型,所以我需要为 N 个泛化方法定义 N 个回调吗?
这是课程:
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);
【问题讨论】:
如果我理解正确,您的假设是正确的。您将需要定义N
回调。从好的方面来说,你只会做一次,所以没什么大不了的,只是一些重复的工作:)
好的,谢谢!你能移动你的评论来回答吗,我会关闭这个。
【参考方案1】:
有几种方法可以避免定义 N 个回调:
您可以在 BeginInvoke 调用中将相应的 EndInvoke 方法作为状态传递。例如
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);
您还可以通过将 stateArray[1] 视为 MultiCastDelegate 并在其上使用 DynamicInvoke 来使 Callback 非泛型,但这会很慢。
对于 .Net 2.0 和 3.0,您可以使用反射,例如
Type actionType= result.AsyncDelegate.GetType();
var minfo = actionType.GetMethod("EndInvoke");
object returnValue = minfo.Invoke(res.AsyncDelegate, new object[] ar );
对于 .Net 4.0,您可以使用动态。例如
dynamic action = result.AsyncDelegate;
object returnValue = action.EndInvoke(result);
【讨论】:
谢谢。但其标记为 c# 2.0。用反射调用方法性能很差 即使是动态的也表现不佳。这就是为什么第 1 点是最好的选择,但完全错过了您已将其标记为 C# 2.0... 包括 C# 2.0 的非反射解决方案 不适用于 Execute如果我理解正确,您的假设是正确的。您将需要定义 N
回调。
从好的方面来说,你只会做一次,所以没什么大不了的,只是一些重复性的工作:)
【讨论】:
以上是关于c# 在回调中调用 endinvoke,使用泛型的主要内容,如果未能解决你的问题,请参考以下文章
c#的BeginInvoke和EndInvoke使用demo
c# 从delegate.begininvoke 捕获异常而不调用delegate.endinvoke
异步使用委托delegate --- BeginInvoke和EndInvoke方法