修改:将实际问题移至顶部。
更新:找到了微软的一个例子,最后收集了一些代码。
我的问题是这些:
更多信息如下。
我正在为我的一个类添加异步支持,并且我认为我会这么做。
上课:
public class Calculator
{
public Int32 Add(Int32 a, Int32 b)
{
return a + b;
}
}
我以为我可以这样做:
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);
}
}
这不起作用,因为这两个方法都构造了自己的委托对象,而.EndInvoke调用检查我调用它的委托实例是否与我最初调用BeginInvoke的那个相同。
处理此问题的最简单方法是将引用存储到变量中,如下所示:
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);
}
}
请注意,我完全了解允许同一个类上的多个实例方法同时执行的问题,关于共享状态等。
更新:我在Asynchronous Delegates Programming Sample上发现了Microsoft的此示例。它显示将IAsyncResult引用转换回AsyncResult对象,然后我可以通过AsyncDelegate属性获取原始委托实例。
这是一种安全的方法吗?
换句话说,以下课程是否合适?
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);
}
}
答案 0 :(得分:4)
编辑:如果你只是指代表本身 - 我想你就可以这样做:
public Int32 EndAdd(IAsyncResult ar)
{
var d = (AddDelegate)((AsyncResult)ar).AsyncDelegate;
return d.EndInvoke(ar);
}
您可以随时将其捕获到代理中;类似于此处的内容:Async without the Pain,可让您使用Action
回调(或Action<T>
)。
其他常见模式涉及回调事件,也许ThreadPool.QueueUserWorkItem
;比IAsyncResult
简单得多。
把所有这些放在一起;这里是一个例子,调用者和代码都不需要对IAsyncResult
:
using System;
using System.Runtime.Remoting.Messaging;
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)
{
var d = (AddDelegate)((AsyncResult)ar).AsyncDelegate;
return d.EndInvoke(ar);
}
}
static class Program
{
static void Main()
{
Calculator calc = new Calculator();
int x = 1, y = 2;
Async.Run<int>(
(ac,o)=>calc.BeginAdd(x,y,ac,o),
calc.EndAdd, result =>
{
Console.WriteLine(result());
});
Console.ReadLine();
}
}
static class Async
{
public static void Run<T>(
Func<AsyncCallback, object, IAsyncResult> begin,
Func<IAsyncResult, T> end,
Action<Func<T>> callback)
{
begin(ar =>
{
T result;
try
{
result = end(ar); // ensure end called
callback(() => result);
}
catch (Exception ex)
{
callback(() => { throw ex; });
}
}, null);
}
}
答案 1 :(得分:2)
我总是存储我作为BeginInvoke的AsyncState的一部分调用它的委托实例,这样你总是可以得到它而不必依赖IAsyncResult的特定实现
获得IAsyncResult之后:
IAsyncResult ar; // this has your IAsyncResult from BeginInvoke in it
MethodInvoker d = (MethodInvoker)ar.AsyncState;
d.EndInvoke(ar);