This trap comes from a requirement: the need to process the data asynchronously in the background, after processing the event that triggers the completion of processing, presumably this is written:
New+ = data_loaded; Action<EmployeeCollection> action = (d) = = { dalhelper.fill (data) ; NULL null);
Very simple code, traps are in it. If Dalhelper.fill (data) throws an exception, then the data. Raiseeventloaded () will not execute and depend on data. The code for the loaded event is also not executed, which is a bug where a try...catch statement should be added to the delegate execution, or the EndInvoke method of the delegate is invoked somewhere to handle possible exceptions in the execution.
For such a simple requirement, adding try...catch or invoking the delegate's EndInvoke is too complicated, just want to satisfy if the execution fails, throw the exception, even if the current process is finished. In a one-write, multiple-use principle, a helper class is specifically designed for asynchronous invocation of this type of delegate. The code for the Help class is as follows:
Public classEventhelper { Public Static voidUnsafebegininvoke (Delegate del,params Object[] args) {Asyncfire Asyncfire=invokedelegate; Asyncfire.begininvoke (Del, args, Throwcallback, asyncfire); } Delegate voidAsyncfire (Delegate del,Object[] args); Static voidInvokedelegate (Delegate del,Object[] args) {Del. DynamicInvoke (args); } Static voidthrowcallback (IAsyncResult ar) {asyncfire asyncfire= Ar. AsyncState asAsyncfire; Asyncfire.endinvoke (AR); }}
The core implementation is to encapsulate the invocation of the delegate, call it in another delegate, and then use EndInvoke to release the possible exception for the other delegate, so that you can discover the exception that is thrown when the delegate executes after the simple invocation of BeginInvoke. After this modification, the code just now can be called:
New+ = data_loaded; Action<EmployeeCollection> action = (d) = = { dalhelper.fill (data); Data. Raiseeventloaded ();}; Eventhelper.unsafebegininvoke (action, data);
The code is as simple as the original design, and if there is an exception in the delegate, it can be found, rather than let the error be masked.
In addition, the implementation is not type-safe, type safety can be resolved by overloading, examples are as follows:
Public classEventhelper { Public Static voidUnsafebegininvoke (Delegate del,params Object[] args) {Asyncfire Asyncfire=invokedelegate; Asyncfire.begininvoke (Del, args, Throwcallback, asyncfire); } Delegate voidAsyncfire (Delegate del,Object[] args); Static voidInvokedelegate (Delegate del,Object[] args) {Del. DynamicInvoke (args); } Static voidthrowcallback (IAsyncResult ar) {asyncfire asyncfire= Ar. AsyncState asAsyncfire; Asyncfire.endinvoke (AR); } #regionAdding a type-safe delegate Public Static voidBeginInvoke (Action del) {Unsafebegininvoke (DEL); } Public Static voidBegininvoke<t,u> (action<t,u>del,t T, u u) {Unsafebegininvoke (del,t,u); } Public Static voidBegininvoke<t,u,v> (action<t,u>del,t T, u u, v v) {Unsafebegininvoke (del,t,u,v); } #endregionAdding a type-safe delegate}
View Code
You can add type-safe implementations according to your needs.
Trap handling for BeginInvoke when delegating asynchronous calls