猿问

在Task中捕获异常的最佳方法是什么?

使用System.Threading.Tasks.Task<TResult>,我必须管理可能引发的异常。我正在寻找做到这一点的最佳方法。到目前为止,我已经创建了一个基类,该基类在调用时管理所有未捕获的异常。.ContinueWith(...)


我想知道是否有更好的方法可以做到这一点。甚至是这样做的好方法。


public class BaseClass

{

    protected void ExecuteIfTaskIsNotFaulted<T>(Task<T> e, Action action)

    {

        if (!e.IsFaulted) { action(); }

        else

        {

            Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>

            {

                /* I display a window explaining the error in the GUI 

                 * and I log the error.

                 */

                this.Handle.Error(e.Exception);

            }));            

        }

    }

}   


public class ChildClass : BaseClass

{

    public void DoItInAThread()

    {

        var context = TaskScheduler.FromCurrentSynchronizationContext();

        Task.Factory.StartNew<StateObject>(() => this.Action())

                    .ContinueWith(e => this.ContinuedAction(e), context);

    }


    private void ContinuedAction(Task<StateObject> e)

    {

        this.ExecuteIfTaskIsNotFaulted(e, () =>

        {

            /* The action to execute 

             * I do stuff with e.Result

             */


        });        

    }

}


人到中年有点甜
浏览 1105回答 2
2回答

POPMUISE

有两种方法可以执行此操作,具体取决于您所使用的语言版本。C#5.0以上您可以使用async和await关键字为您简化很多操作。async并且await被引入该语言以简化使用Task Parallel Library的工作,从而避免了您必须使用ContinueWith并允许您以自上而下的方式继续编程。因此,您可以简单地使用try/catch块来捕获异常,如下所示:try{&nbsp; &nbsp; // Start the task.&nbsp; &nbsp; var task = Task.Factory.StartNew<StateObject>(() => { /* action */ });&nbsp; &nbsp; // Await the task.&nbsp; &nbsp; await task;}catch (Exception e){&nbsp; &nbsp; // Perform cleanup here.}请注意,封装上述内容的方法必须使用已async应用关键字,这样您才可以使用await。C#4.0及以下您可以使用从枚举中获取值的ContinueWith重载来处理异常,如下所示:TaskContinuationOptions// Get the task.var task = Task.Factory.StartNew<StateObject>(() => { /* action */ });// For error handling.task.ContinueWith(t => { /* error handling */ }, context,&nbsp; &nbsp; TaskContinuationOptions.OnlyOnFaulted);在OnlyOnFaulted该成员TaskContinuationOptions枚举指示应继续只当先行任务抛出异常执行。当然,您可以有多个调用来ContinueWith取消同一先决条件,从而处理非例外情况:// Get the task.var task = new Task<StateObject>(() => { /* action */ });// For error handling.task.ContinueWith(t => { /* error handling */ }, context,&nbsp;&nbsp; &nbsp; TaskContinuationOptions.OnlyOnFaulted);// If it succeeded.task.ContinueWith(t => { /* on success */ }, context,&nbsp; &nbsp; TaskContinuationOptions.OnlyOnRanToCompletion);// Run task.task.Start();

慕慕森

您可以创建一些自定义的Task工厂,该工厂将生成嵌入了异常处理过程的Task。像这样:using System;using System.Threading.Tasks;class FaFTaskFactory{&nbsp; &nbsp; public static Task StartNew(Action action)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return Task.Factory.StartNew(action).ContinueWith(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AggregateException exception = c.Exception;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Your Exception Handling Code&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously&nbsp; &nbsp; &nbsp; &nbsp; ).ContinueWith(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Your task accomplishing Code&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously&nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; }&nbsp; &nbsp; public static Task StartNew(Action action, Action<Task> exception_handler, Action<Task> completion_handler)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return Task.Factory.StartNew(action).ContinueWith(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exception_handler,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously&nbsp; &nbsp; &nbsp; &nbsp; ).ContinueWith(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; completion_handler,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously&nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; }};您可以在客户端代码中忘记从该工厂生成的任务的异常处理。同时,您仍然可以等待此类任务的完成或以“一劳永逸”的方式使用它们:var task1 = FaFTaskFactory.StartNew( () => { throw new NullReferenceException(); } );var task2 = FaFTaskFactory.StartNew( () => { throw new NullReferenceException(); },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c => {&nbsp; &nbsp; Console.WriteLine("Exception!"); },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c => {&nbsp; &nbsp; Console.WriteLine("Success!"&nbsp; ); } );task1.Wait(); // You can omit thistask2.Wait(); // You can omit this但是,老实说,我不太确定为什么要使用完成处理代码。无论如何,此决定取决于您的应用程序的逻辑。
随时随地看视频慕课网APP
我要回答