這個陷阱來自於一個需求:需要異步在後台處理數據,處理完後觸發處理完成的事件,大概是這麼寫的:
EmployeeCollection data = +=<EmployeeCollection> action = (d) =>, );
挺簡單的代碼,陷阱也在其中。假如DalHelper.Fill(data)拋出了一個異常,那麼對data.RaiseEventLoaded()就不會執行,依賴於data.Loaded事件的代碼也不會執行,這是一個bug,應該在委托執行中加入一個try...catch語句,或者在某個地方調用委托的EndInvoke方法,來處理執行中可能的異常。
為了這麼一個簡單的需求,加入try...catch或者調用委托的EndInvoke都太復雜了,僅僅只想滿足假如執行失敗,就把異常拋出來,即使將當前進程結束也沒事。本著一次編寫,多次使用的原則,專門設計了一個幫助類來專職這類委托的異步調用。幫助類的代碼如下:
UnsafeBeginInvoke(Delegate del, = AsyncFire(Delegate del, InvokeDelegate(Delegate del, = ar.AsyncState
核心實現是將委托的調用封裝起來,在另外一個委托中去調用,然後對另外的那個委托用EndInvoke來釋放可能的異常,這樣就能夠發現單純的調用BeginInvoke後委托執行時引發的異常。這樣修改後,剛才的代碼就可以這樣來調用:
EmployeeCollection data = +=<EmployeeCollection> action = (d) =>
代碼還如最初的設計那麼簡單,而且真要是委托中發生了異常,也能夠發現這個錯誤,而不是讓這個錯誤被掩蓋。
另外,剛才的實現不是類型安全的,類型安全可以通過重載來解決,例子如下:
View Code各位同學可以根據自己的需要添加類型安全的實現。