访问Task.ContinueWith中的值
本文关键字:ContinueWith Task 访问 | 更新日期: 2023-09-27 18:14:57
我用下面的代码开始一个任务:
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
在执行时能够访问它所需的值?
首先,我甚至不确定您的情况是否需要继续。您的代码可以简化为如下内容:
var taskWithToken = new Task(() =>
{
new ProcessMyCommand(_unitOfWork, ..., batchRunId, token).Execute();
// code from the continuation here
},
token);
但是,如果您确实想使用ContinueWith()
,并且由于ReSharper警告而担心使用它,那么您不必这样做。大多数情况下,像这样的代码是完全没问题的,您可以忽略警告。
长版本:当你写一个lambda引用了封闭范围(所谓的闭包)的东西时,编译器必须为此生成代码。具体如何做是一个实现细节,但是当前的编译器为一个方法中的所有闭包生成一个闭包类。
在您的情况下,这意味着编译器生成一个包含局部变量this
(因为_unitOfWork
)、request
和batchRunId
(可能还有您没有显示的其他变量)的类。这个闭包对象在new Task
lambda和ContinueWith()
lambda之间共享,即使第二个lambda不使用request
或this
。只要第二个lambda从某处被引用,这些对象就不能被垃圾收集,即使它们不能被访问。
所以,这种情况可能导致内存泄漏,我相信这就是ReSharper警告你的原因。但在几乎所有情况下,这种内存泄漏要么不存在(因为第二个lambda的引用时间并不比第一个长),要么非常小。因此,大多数时候,您可以安全地忽略该警告。但是如果你发现了神秘的内存泄漏,你应该调查你使用lambdas的方式,特别是在你得到这个警告的地方。
您可以创建您的MyTaskData
类来存储您的数据和结果,它也可以存储MyTaskData PreviousTaskData
属性(从上一个任务)创建结果链表。创建一个Task<MyTaskData>
,在里面,最后,你的return myNewTaskData;
。然后是ContinueWith<MyTaskData>(...)
,您可以通过Task.Result
属性获得之前的结果。至于在取消的Task
上继续ContinueWith
有一个带有TaskContinuationOptions
参数(MSDN)的变体,您可以指定NotOnCanceled