我如何避免使用的BeginInvoke和EndInvoke时绕过/存储的委托? [英] How can I avoid having to pass around/store a delegate when using BeginInvoke and EndInvoke?
问题描述
修改:移动到顶部的实际问题。
更新:发现微软为例,在卷起在年底一些code
我的问题是:
- 它是安全的调用多个BeginInvoke的上相同的委托实例调用,还是我要建立一个新的委托实例每个飞行方法调用?
- 如果我有构造新的记录每一个,有一些方法来获得原始委托持币观望的IAsyncResult价值?
- 有一些其他的,更好的,方式异步支持我的课比添加使用委托?
更多信息如下:
我加入一类矿井异步支持,我想我会做简单的。
就拿这个类:
公共类计算器
{
公众的Int32添加(的Int32一个,的Int32 B)
{
返回A + B;
}
}
我以为我可以简单地这样做:
公共类计算器
{
私人委托的Int32 AddDelegate(一的Int32,的Int32 B);
公众的Int32添加(的Int32一个,的Int32 B)
{
返回A + B;
} 公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,
AsyncCallback的回调,obj对象)
{
返回新AddDelegate(添加).BeginInvoke(A,B,回调,OBJ);
} 公众的Int32 EndAdd(IAsyncResult的AR)
{
返回新AddDelegate(添加).EndInvoke(AR);
}
}
这是不行的,因为这两个方法都构建自己的委托对象,并调用.EndInvoke检查是否委托实例我把它上是一样的一个我原来叫上的BeginInvoke。
来处理这将是只是一个参考存储到一个变量,这样最简单的方式:
公共类计算器
{
私人委托的Int32 AddDelegate(一的Int32,的Int32 B);
私人AddDelegate _add; 公共计算器()
{
_add =新AddDelegate(添加);
} 公众的Int32添加(的Int32一个,的Int32 B)
{
返回A + B;
} 公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,
AsyncCallback的回调,obj对象)
{
返回_Add.BeginInvoke(A,B,回调,OBJ);
} 公众的Int32 EndAdd(IAsyncResult的AR)
{
返回_Add.EndInvoke(AR);
}
}
请注意,我是完全明白的问题,允许在同一类的多个实例方法在同一时间执行,关于共享状态,等等。
更新:我发现这里的这个例子微软的异步委托编程示例。这表明铸造 IAsyncResult的参考回到一个的 AsyncResult 对象,然后我可以得到原来的委托例如通过<一个href=\"http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.asyncresult.asyncdelegate.aspx\"相对=nofollow> AsyncDelegate 属性。
这是一种安全的方法?
在换句话说,就是下面的类罚款?
公共类计算器
{
私人委托的Int32 AddDelegate(一的Int32,的Int32 B); 公众的Int32添加(的Int32一个,的Int32 B)
{
返回A + B;
} 公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,AsyncCallback的回调,obj对象)
{
返回新AddDelegate(添加).BeginInvoke(A,B,回调,OBJ);
} 公众的Int32 EndAdd(IAsyncResult的AR)
{
AddDelegate德尔=(AddDelegate)((AsyncResult)AR).AsyncDelegate;
返回del.EndInvoke(AR);
}
}
编辑:如果你只是意味着代表本身 - 我的认为的你可以这样做:
公众的Int32 EndAdd(IAsyncResult的AR)
{
变种D =(AddDelegate)((AsyncResult)AR).AsyncDelegate;
返回d.EndInvoke(AR);
}
您可以随时捕捉到它的代表;像在这里:异步无疼痛,它可以让你只使用动作
的回调(或动作&LT; T&GT;
)。
其他常见的模式涉及回调的事件,也许 ThreadPool.QueueUserWorkItem
;比的IAsyncResult
简单多了。
放在一起这一切;这里的地方需要得到强调有关既不呼叫者也不是code为例的IAsyncResult
:
使用系统;
使用System.Runtime.Remoting.Messaging;
公共类计算器
{
私人委托的Int32 AddDelegate(一的Int32,的Int32 B);
公众的Int32添加(的Int32一个,的Int32 B)
{
返回A + B;
} 公众的IAsyncResult BeginAdd(一的Int32,的Int32 B,
AsyncCallback的回调,obj对象)
{
返回新AddDelegate(添加).BeginInvoke(A,B,回调,OBJ);
} 公众的Int32 EndAdd(IAsyncResult的AR)
{
变种D =(AddDelegate)((AsyncResult)AR).AsyncDelegate;
返回d.EndInvoke(AR);
}
}
静态类节目
{
静态无效的主要()
{
计算器计算值=新的计算器();
INT X = 1,Y = 2;
Async.Run&LT; INT&GT;(
(AC,0)=&GT; calc.BeginAdd(X,Y,交流,O),
calc.EndAdd,结果=&GT;
{
Console.WriteLine(结果());
});
到Console.ReadLine();
}
}
静态类异步
{
公共静态无效润LT; T&GT;(
FUNC&LT;的AsyncCallback,对象,IAsyncResult的&GT;开始,
FUNC&LT; IAsyncResult的,T&GT;结束,
动作&LT;&Func键LT; T&GT;&GT;回电话)
{
开始(AR =&GT;
{
Ť结果;
尝试
{
结果=结束(AR); //确保到底叫什么
回调(()=&GT;结果);
}
赶上(异常前)
{
回调(()=&GT; {抛出前;});
}
}, 空值);
}
}
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:
- Is it safe to call multiple BeginInvoke calls on the same delegate instance, or do I have to construct a new delegate instance for each in-flight method call?
- If I have to construct new instances for each, is there some way to get hold of the original delegate out of the IAsyncResult value?
- Is there some other, better, way to add asynchronous support to my class than using delegates?
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.
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. 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);
}
}
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>
).
Other common patterns involve events for the callback, and perhaps ThreadPool.QueueUserWorkItem
; a lot simpler than 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屋!