程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 委托異步調用時BeginInvoke的陷阱處理,begininvoke陷阱

委托異步調用時BeginInvoke的陷阱處理,begininvoke陷阱

編輯:C#入門知識

委托異步調用時BeginInvoke的陷阱處理,begininvoke陷阱


這個陷阱來自於一個需求:需要異步在後台處理數據,處理完後觸發處理完成的事件,大概是這麼寫的:

復制代碼
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

各位同學可以根據自己的需要添加類型安全的實現。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved