访问Task.ContinueWith中的值

时间:2013-05-23 14:05:53

标签: c# task-parallel-library

我正在使用以下代码开始一项任务:

var token = tokenSource.Token;
var taskWithToken = new Task(() =>
        new ProcessMyCommand(_unitOfWork, ..., batchRunId, token).Execute(), 
        token);

在我的继续中,我需要知道batchRunId以及可能在...中列出的其他一些变量,但是,它并不能说明这是可能的???

taskWithToken.ContinueWith(task =>
        {
            if (!task.IsCanceled)
                return;

            //TODO: make sure no more subsequent runs happen

            //TODO: sync with source data
        }
    );

我有什么遗失的吗?如何通过访问所需的值来确保.ContinueWith执行?

2 个答案:

答案 0 :(得分:4)

首先,我甚至不确定你的案子是否需要延续。您的代码可以简化为:

var taskWithToken = new Task(() =>
    {
        new ProcessMyCommand(_unitOfWork, ..., batchRunId, token).Execute();

        // code from the continuation here
    },
    token);

但是如果你确实想要使用ContinueWith()并且由于ReSharper警告你担心使用它,那么你不必这样做。大多数情况下,这样的代码非常好,您可以忽略警告。

更长的版本:当你编写一个引用封闭范围(所谓的closure)的lambda时,编译器必须为此生成代码。这究竟是一个实现细节,但是当前编译器为单个方法中的所有闭包生成一个闭包类。

在您的情况下,这意味着编译器会生成一个包含本地this(因为_unitOfWork),requestbatchRunId(以及其他人)的类你没有表现出来)。这个闭包对象在new Task lambda和ContinueWith() lambda之间共享,即使第二个lambda不使用requestthis。只要从某个地方引用第二个lambda,就不能对这些对象进行垃圾回收,即使它们无法从中进行访问。

所以,这种情况可能会导致内存泄漏,我相信这就是ReSharper警告你的原因。但几乎在所有情况下,这种内存泄漏都不存在(因为第二个lambda的引用时间不比第一个lambda长)或者它非常小。因此,大多数情况下,您可以放心地忽略该警告。但如果你得到神秘的内存泄漏,你应该调查你使用lambdas的方式,特别是你得到这个警告的地方。

答案 1 :(得分:2)

您可以创建MyTaskData类来存储数据和结果,也可以存储MyTaskData PreviousTaskData属性(来自上一个任务),创建结果链表。在其中创建一个Task<MyTaskData>,最后是return myNewTaskData;。然后在ContinueWith<MyTaskData>(...)内,您可以通过Task.Result属性获取之前的结果。 至于已取消Task ContinueWith的延续,其中包含TaskContinuationOptions参数(MSDN)的变体,您可以在其中指定NotOnCanceled