2

我已经实现了在后台运行繁重任务的辅助方法

它接受多个代表并且不阻塞:

  • 异步部分
  • 成功部分(GUI)
  • 异步部分失败(GUI)
  • 最后(GUI)(可选)

每个 gui 部分都可以开始它自己的序列,即发生对我的辅助方法的递归调用。但是我想在附加任务完成时将任何部分视为已完成。

这张图片解释了我的意思:

在此处输入图像描述

为了提供这种条件,我将我的异步任务创建为附加到父级,这给了我需要的东西。
我唯一的问题是,在 TPL for .NET v4DenyChildAttach选项中不存在,所以当我的方法在其他任务中被调用时,它会附加到这个任务。
我将创建一个带有参数的重载来指示附加的需要,但是我想要以下默认行为:

如果递归调用,则附加,否则除非明确说明,否则不要附加。
明确地说,我应该设置一些指示递归的上下文,但不明白如何......

PS Now 方法看起来像这样(对于 Action、Func 有很多重载):

public static CancellationTokenSource ExecuteBlockingOperation(Action action,
            Action completition,
            Action<AggregateException> onException,
            Action<bool, bool, bool> @finally = null)
        {
            if (action == null)
                throw new ArgumentNullException("action");

            if (completition == null)
                throw new ArgumentNullException("completition");

            if (onException == null)
                throw new ArgumentNullException("onException");

            var cts = new CancellationTokenSource();
            var token = cts.Token;

            var scheduler = SynchronizationContext.Current == null? TaskScheduler.Default : TaskScheduler.FromCurrentSynchronizationContext();
            var successfullyCompleted = false;

            var task = new Task(action, TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent);
            var onFault = task.ContinueWith(asyncPartTask => onException(asyncPartTask.Exception),
                CancellationToken.None,
                TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent,
                scheduler);

            var onSuccess = task.ContinueWith(asyncPart =>
                {
                    if (!token.IsCancellationRequested)
                    {
                        completition();
                        successfullyCompleted = true;
                    }
                }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent, scheduler);

            if (@finally != null)
            {
                Task.Factory.ContinueWhenAll(new[] { onSuccess, onFault },
                    tasks =>
                    {
                        var isSuccess = task.Status == TaskStatus.RanToCompletion;
                        @finally(isSuccess, token.IsCancellationRequested, successfullyCompleted);
                    },
                    CancellationToken.None,
                    TaskContinuationOptions.AttachedToParent, scheduler);
            }

            task.Start();

            return cts;

        }
4

1 回答 1

0

我认为使用AttachedToParent非常笨拙。相反,您可以做的是Task通过更改completitionFunc<Task>. 这样,您可以控制何时执行什么延续。

为此,您需要更改onSuccess为:

var onSuccess = task.ContinueWith(asyncPart =>
    {
        token.ThrowIfCancellationRequested();

        return completion();
    }, token, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler).Unwrap();

这也很可能意味着ExecuteBlockingOperation()需要返回Task执行的@finally,但我认为这不应该是一个问题。

于 2013-04-04T17:52:58.667 回答