TaskContinuationOptions.OnlyOnFaulted不考虑使用异常的流量控制

本文关键字:异常 流量控制 OnlyOnFaulted 不考虑 TaskContinuationOptions | 更新日期: 2023-09-27 18:05:49

在我的印象中,用异常控制流被认为是一种不好的做法。

那你为什么要这样做呢:

var task = Task.Factory
            .StartNew(() => command.Execute());
task.ContinueWith(t => 
                      {
                          // success callback
                      }, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t =>
                      {
                          Log.Error(string.Format("'{0}' failed.", command.GetType()), t.Exception);
                          // error callback
                      }, TaskContinuationOptions.OnlyOnFaulted);

当你可以很容易地catch command.Execute()内的异常,有什么我在这里错过了?任务可以抛出与它们正在执行的代码无关的异常吗?

编辑:如果我们使用c# 5的asyncawait关键字,你会说这样会更好吗?还是像上面的例子那样,捕获所有的关键字真的无关紧要?

public class AsyncFooCommand : AsyncCommandBase<Bar>
{
    public override Bar Execute()
    {
        try
        {
            var bar = // Do something that can throw SpecificException
            Successful = true;
            return bar;
        }
        catch (SpecificException ex)
        {
            // Log
        }
    }
}
public static class AsyncCommandExecutor<T>
{
    // NOTE: don't care about sharing this between instances.
    // ReSharper disable StaticFieldInGenericType
    private static readonly ILog Log = LogManager.GetLogger(typeof(Infrastructure.Commands.AsyncCommandExecutor<>));
    // ReSharper restore StaticFieldInGenericType
    public static async Task<T> Execute(IAsyncCommand<T> command, Action<T> success = null, Action error = null)
    {
        var task = Task.Factory
            .StartNew(() =>
            {
                return command.Execute();
            });
        task.ContinueWith(t => Log.Error(string.Format("'{0}' failed, something terrible happened.", command.GetType()), t.Exception),
            TaskContinuationOptions.OnlyOnFaulted);
        T result = await task;
        if (success != null && command.Successful)
        {
            success(result);
        }
        if (error != null && !command.Successful)
        {
            error();
        }
        return result;
    }
}

TaskContinuationOptions.OnlyOnFaulted不考虑使用异常的流量控制

当然可以,也就不需要继续了。这只是一种不同的方法。

但是,如果您在任务中捕获异常并运行到完成,那么对于外部世界来说,任务看起来是成功的,而不是失败的。如果您有TaskContinuationOptions.OnlyOnRanToCompletion或其他类似选项的其他延续,并且您在技术上未能执行该命令(并且刚刚捕获了异常),那么该任务可能会在需要成功运行前项时继续运行。它更多的是关于任务状态管理。