委托异步调用时BeginInvoke的陷阱处理
2014-04-22 22:17
260 查看
这个陷阱来自于一个需求:需要异步在后台处理数据,处理完后触发处理完成的事件,大概是这么写的:
EmployeeCollection data = new EmployeeCollection();
data.Loaded += data_Loaded;
Action<EmployeeCollection> action = (d) => {
DalHelper.Fill(data);
data.RaiseEventLoaded();
};
action.BeginInvoke(data, null, null);
挺简单的代码,陷阱也在其中。假如DalHelper.Fill(data)抛出了一个异常,那么对data.RaiseEventLoaded()就不会执行,依赖于data.Loaded事件的代码也不会执行,这是一个bug,应该在委托执行中加入一个try…catch语句,或者在某个地方调用委托的EndInvoke方法,来处理执行中可能的异常。
为了这么一个简单的需求,加入try…catch或者调用委托的EndInvoke都太复杂了,仅仅只想满足假如执行失败,就把异常抛出来,即使将当前进程结束也没事。本着一次编写,多次使用的原则,专门设计了一个帮助类来专职这类委托的异步调用。帮助类的代码如下:
public class EventHelper {
public static void UnsafeBeginInvoke(Delegate del,params object[] args){
AsyncFire asyncFire = InvokeDelegate;
asyncFire.BeginInvoke(del, args, ThrowCallback, asyncFire);
}
delegate void AsyncFire(Delegate del,object[] args);
static void InvokeDelegate(Delegate del,object[] args){
del.DynamicInvoke(args);
}
static void ThrowCallback(IAsyncResult ar) {
AsyncFire asyncFire = ar.AsyncState as AsyncFire;
asyncFire.EndInvoke(ar);
}
}
核心实现是将委托的调用封装起来,在另外一个委托中去调用,然后对另外的那个委托用EndInvoke来释放可能的异常,这样就能够发现单纯的调用BeginInvoke后委托执行时引发的异常。这样修改后,刚才的代码就可以这样来调用托福答案
EmployeeCollection data = new EmployeeCollection();
data.Loaded += data_Loaded;
Action<EmployeeCollection> action = (d) => {
DalHelper.Fill(data);
data.RaiseEventLoaded();
};
EventHelper.UnsafeBeginInvoke(action, data);
代码还如最初的设计那么简单,而且真要是委托中发生了异常,也能够发现这个错误,而不是让这个错误被掩盖。
另外,刚才的实现不是类型安全的,类型安全可以通过重载来解决,例子如下:
public class EventHelper {
public static void UnsafeBeginInvoke(Delegate del,params object[] args){
AsyncFire asyncFire = InvokeDelegate;
asyncFire.BeginInvoke(del, args, ThrowCallback, asyncFire);
}
delegate void AsyncFire(Delegate del,object[] args);
static void InvokeDelegate(Delegate del,object[] args){
del.DynamicInvoke(args);
}
static void ThrowCallback(IAsyncResult ar) {
AsyncFire asyncFire = ar.AsyncState as AsyncFire;
asyncFire.EndInvoke(ar);
}
#region 添加类型安全的委托
public static void BeginInvoke(Action del){
UnsafeBeginInvoke(del);
}
public static void BeginInvoke<T,U>(Action<T,U> del,T t, U u){
UnsafeBeginInvoke(del,t,u);
}
public static void BeginInvoke<T,U,V>(Action<T,U> del,T t, U u, V v){
UnsafeBeginInvoke(del,t,u,v);
}
#endregion 添加类型安全的委托
}
View Code
可以根据自己的需要添加类型安全的实现雅思答案
EmployeeCollection data = new EmployeeCollection();
data.Loaded += data_Loaded;
Action<EmployeeCollection> action = (d) => {
DalHelper.Fill(data);
data.RaiseEventLoaded();
};
action.BeginInvoke(data, null, null);
挺简单的代码,陷阱也在其中。假如DalHelper.Fill(data)抛出了一个异常,那么对data.RaiseEventLoaded()就不会执行,依赖于data.Loaded事件的代码也不会执行,这是一个bug,应该在委托执行中加入一个try…catch语句,或者在某个地方调用委托的EndInvoke方法,来处理执行中可能的异常。
为了这么一个简单的需求,加入try…catch或者调用委托的EndInvoke都太复杂了,仅仅只想满足假如执行失败,就把异常抛出来,即使将当前进程结束也没事。本着一次编写,多次使用的原则,专门设计了一个帮助类来专职这类委托的异步调用。帮助类的代码如下:
public class EventHelper {
public static void UnsafeBeginInvoke(Delegate del,params object[] args){
AsyncFire asyncFire = InvokeDelegate;
asyncFire.BeginInvoke(del, args, ThrowCallback, asyncFire);
}
delegate void AsyncFire(Delegate del,object[] args);
static void InvokeDelegate(Delegate del,object[] args){
del.DynamicInvoke(args);
}
static void ThrowCallback(IAsyncResult ar) {
AsyncFire asyncFire = ar.AsyncState as AsyncFire;
asyncFire.EndInvoke(ar);
}
}
核心实现是将委托的调用封装起来,在另外一个委托中去调用,然后对另外的那个委托用EndInvoke来释放可能的异常,这样就能够发现单纯的调用BeginInvoke后委托执行时引发的异常。这样修改后,刚才的代码就可以这样来调用托福答案
EmployeeCollection data = new EmployeeCollection();
data.Loaded += data_Loaded;
Action<EmployeeCollection> action = (d) => {
DalHelper.Fill(data);
data.RaiseEventLoaded();
};
EventHelper.UnsafeBeginInvoke(action, data);
代码还如最初的设计那么简单,而且真要是委托中发生了异常,也能够发现这个错误,而不是让这个错误被掩盖。
另外,刚才的实现不是类型安全的,类型安全可以通过重载来解决,例子如下:
public class EventHelper {
public static void UnsafeBeginInvoke(Delegate del,params object[] args){
AsyncFire asyncFire = InvokeDelegate;
asyncFire.BeginInvoke(del, args, ThrowCallback, asyncFire);
}
delegate void AsyncFire(Delegate del,object[] args);
static void InvokeDelegate(Delegate del,object[] args){
del.DynamicInvoke(args);
}
static void ThrowCallback(IAsyncResult ar) {
AsyncFire asyncFire = ar.AsyncState as AsyncFire;
asyncFire.EndInvoke(ar);
}
#region 添加类型安全的委托
public static void BeginInvoke(Action del){
UnsafeBeginInvoke(del);
}
public static void BeginInvoke<T,U>(Action<T,U> del,T t, U u){
UnsafeBeginInvoke(del,t,u);
}
public static void BeginInvoke<T,U,V>(Action<T,U> del,T t, U u, V v){
UnsafeBeginInvoke(del,t,u,v);
}
#endregion 添加类型安全的委托
}
View Code
可以根据自己的需要添加类型安全的实现雅思答案
相关文章推荐
- 委托异步调用时BeginInvoke的陷阱处理
- [ 在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。]错误的处理
- winform 利用 多线程 处理窗体假死,利用 Invoke BeginInvoke 处理子线程调用 UI 控件报错的问题
- 在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke
- "在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke"
- Control的Invoke和BeginInvoke 是相对于支线线程(因为一般在支线线程中调用,用来更新主线程ui)Invoke立即插入主线程中执行,而BeginInvoke 要等主线程结束才执行
- "在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke"
- 安装SQL Server出现在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke的错误解决办法
- C# 异步调用的学习 BeginInvoke ManualRestEvent
- 对于事件不能调用BeginInvoke,可改用另外一层包装
- SQL Server 2008安装时出现不能在控件上调用 Invoke 或 BeginInvoke错误的方法,为sql server代理服务提供的凭据无效。若要继续操作
- WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用 Control 不能在创建它的 Thread 之外被调用。但可以通过 invoke 来保证 C
- 普通方法调用,Invoke,begininvoke三者的区别总结及异步与同步的区别总结
- BeginInvoke四种异步调用学习体会
- C#_delegate - 异步调用实例 BeginInvoke EndInvoke event
- Control的Invoke和BeginInvoke 是相对于支线线程(因为一般在支线线程中调用,用来更新主线程ui)Invoke立即插入主线程中执行,而BeginInvoke 要等主线程结束才执行
- 线程间异步调用BeginInvoke
- WIN7可中SQL SERVER 2008安装时出现不能在控件上调用 Invoke 或 BeginInvoke错误(终极解决方法)
- 线程调用BeginInvoke
- 安装SQL Server出现在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke的错误解决办法