使用BeginInvoke和EndInvoke时,如何避免传递/存储代理? [英] How can I avoid having to pass around/store a delegate when using BeginInvoke and EndInvoke?
问题描述
修改:将实际问题移动到顶端。
Edit: Moved the actual question to the top.
更新:Microsoft发现了一个示例,
Update: Found an example by Microsoft, tucked on some more code at the end.
我的问题是这些:
- 在同一个委托实例上调用多个BeginInvoke调用是安全的,还是为每个正在运行的方法调用构建一个新的委托实例?
- 如果我必须构建新的有些方法可以让IAsyncResult值保留原来的代理?
- 有没有其他更好的方式来添加异步支持到我的类,而不是使用代理?
更多信息如下。
我在添加异步支持我的班级,以为我会这么简单。
I am adding asynchronous support to a class of mine, and thought I'd do it simple.
参加这个课程:
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的相同。
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.
处理这个最简单的方法是将参考存储到变量中,如下所示:
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.
更新:我在这里发现这个例子是由Microsoft在异步代理编程示例。它显示将 IAsyncResult 引用转发到 AsyncResult 对象,然后我可以得到原始委托实例通过 AsyncDelegate 属性
Update: I found this example here by Microsoft on Asynchronous Delegates Programming Sample. It shows casting the IAsyncResult reference back to an AsyncResult object, and then I can get the original delegate instance through the AsyncDelegate property.
这是一个安全的方法吗?
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);
}
}
推荐答案
:如果你只是代表委托本身 - 我想你可以这么做:
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);
}
你可以随时捕获它进入代表像这样: Async without the Pain ,这让你只需使用 Action
回调(或 Action< T>
)。
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>
).
其他常见的模式涉及回调的事件,也许 ThreadPool.QueueUserWorkItem
;比 IAsyncResult
简单得多。
Other common patterns involve events for the callback, and perhaps 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
:
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);
}
}
这篇关于使用BeginInvoke和EndInvoke时,如何避免传递/存储代理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!