[英]How can I avoid having to pass around/store a delegate when using BeginInvoke and EndInvoke?
Edit : Moved the actual question to the top. 编辑 :将实际问题移至顶部。
Update : Found an example by Microsoft, tucked on some more code at the end. 更新 :发现微软的一个例子,最后隐藏了一些代码。
My questions are these: 我的问题是这些:
More info follows. 更多信息如下。
I am adding asynchronous support to a class of mine, and thought I'd do it simple. 我正在为我的一类添加异步支持,并认为我会这么做。
Take this class: 上这堂课:
public class Calculator
{
public Int32 Add(Int32 a, Int32 b)
{
return a + b;
}
}
I thought I could simply do this: 我以为我可以这样做:
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);
}
}
This doesn't work, as the two methods each construct their own delegate object, and the .EndInvoke call checks to see if the delegate instance i call it on is the same as the one I originally called BeginInvoke on. 这不起作用,因为两个方法各自构造自己的委托对象,并且.EndInvoke调用检查以查看我调用它的委托实例是否与我最初调用BeginInvoke的实例相同。
The simplest way to handle this would be to just store a reference into a variable, like this: 处理这个问题的最简单方法是将引用存储到变量中,如下所示:
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);
}
}
Note that I'm fully aware of problems with allowing multiple instance methods on the same class to execute at the same time, with regards to shared state, etc. 请注意,我完全了解允许同一个类上的多个实例方法同时执行的问题,关于共享状态等。
Update : I found this example here by Microsoft on Asynchronous Delegates Programming Sample . 更新 :我在这里通过Microsoft在异步委托编程示例中找到了这个示例。 It shows casting the IAsyncResult reference back to an AsyncResult object, and then I can get the original delegate instance through the AsyncDelegate property.
它显示了将IAsyncResult引用转换回AsyncResult对象,然后我可以通过AsyncDelegate属性获取原始委托实例。
Is this a safe approach? 这是一种安全的方法吗?
In other words, is the following class fine? 换句话说,以下课程是否合适?
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);
}
}
Edit: if you just mean the delegate itself - I think you can just do: 编辑:如果你只是指代表本身 - 我想你可以这样做:
public Int32 EndAdd(IAsyncResult ar)
{
var d = (AddDelegate)((AsyncResult)ar).AsyncDelegate;
return d.EndInvoke(ar);
}
You could always capture it into the delegate; 你总是可以把它捕获到代表中; something like here: Async without the Pain , which lets you just use an
Action
callback (or Action<T>
). 像这里的东西: Async without the Pain ,它允许你只使用
Action
回调(或Action<T>
)。
Other common patterns involve events for the callback, and perhaps ThreadPool.QueueUserWorkItem
; 其他常见模式涉及回调事件,也许还有
ThreadPool.QueueUserWorkItem
; a lot simpler than IAsyncResult
. 比
IAsyncResult
简单得多。
Putting all this together; 将所有这些放在一起; here's an example where neither the caller nor the code needs to get stressed about
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);
}
}
I always store the delegate instance I called it on as part of the AsyncState of a BeginInvoke, that way you can always get it without having to rely on a specific implementation of IAsyncResult 我总是存储我作为BeginInvoke的AsyncState的一部分调用它的委托实例,这样你总是可以得到它而不必依赖于IAsyncResult的特定实现
Once you've got your IAsyncResult: 一旦你得到了你的IAsyncResult:
IAsyncResult ar; // this has your IAsyncResult from BeginInvoke in it
MethodInvoker d = (MethodInvoker)ar.AsyncState;
d.EndInvoke(ar);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.