0

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

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执行时可以访问所需的值?

4

2 回答 2

4

首先,我什至不确定您是否需要继续处理您的案件。您的代码可以简化为:

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

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

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

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

在您的情况下,这意味着编译器生成一个包含本地变量的类this(因为_unitOfWorkrequestbatchRunId(可能还有其他您没有显示的)。new Task这个闭包对象在lambda 和lambda之间共享ContinueWith(),即使第二个 lambda 不使用requestor this。只要从某个地方引用了第二个 lambda,这些对象就不能被垃圾回收,即使它们不能被它访问。

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

于 2013-05-23T21:34:39.203 回答
2

您可以创建您的MyTaskData类来存储您的数据和结果,它还可以存储MyTaskData PreviousTaskData属性(来自以前的任务)创建结果的链接列表。创建一个Task<MyTaskData>内部,最后,您return myNewTaskData;. 然后ContinueWith<MyTaskData>(...)在里面你可以通过Task.Result属性得到以前的结果。至于取消的继续Task ContinueWith有一个带有TaskContinuationOptions参数(MSDN)的变体,您可以在其中指定NotOnCanceled

于 2013-05-23T14:29:54.757 回答