我有一个遗留场景,其中使用 ref bool
向实现发送取消信号。现在,我想调用一个基于 Task
的库方法,该方法采用 CancellationToken
实例,我也希望在 bool 值更改时取消该实例。
这就是我必须处理的事情:
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
DoThat();
...
}
}
这就是我想做的:
Task MethodAsync(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
await DoTheNewThingAsync(isCancelled.ToCancellationToken());
DoThat();
...
}
}
ToCancellationToken()
当然在此上下文中不存在,仅用于显示意图。
我尝试创建 CancellationTokenSource
的自定义实现,但该类中没有任何可以使用的虚拟内容。也不可能直接创建自定义 CancellationToken
,因为它是一个 struct
并且无法继承。
我知道使用 ref bool
是一种糟糕的做法,但我目前无法更改依赖它的底层实现,因此我需要一种方法来使用它的值作为取消基于任务的调用机制。
最佳答案
这很复杂。出于以下几个原因:
- 您无法通过
ref
将参数传递给async
方法。您正在使用await
,但要使用await
,您的方法需要标记为async
。并且async
方法不能有ref
参数。例如,这不会编译:
async Task MethodAsync(ref bool isCancelled)
{
while (!isCancelled)
{
DoThis();
await DoTheNewThingAsync(isCancelled.ToCancellationToken());
DoThat();
}
}
这会给你编译器错误:
CS1988: Async methods cannot have ref, in or out parameters
- 您不能在匿名方法中使用
ref
参数。我考虑过使用Timer
来检查变量。像这样的事情:
public static CancellationToken ToCancellationToken(ref bool isCancelled)
{
var tokenSource = new CancellationTokenSource();
var timer = new System.Timers.Timer()
{
AutoReset = true,
Interval = 100
};
timer.Elapsed += (source, e) =>
{
if (isCancelled)
{
tokenSource.Cancel();
timer.Dispose();
}
};
timer.Enabled = true;
return tokenSource.Token;
}
但这会给你编译器错误:
CS1628: Cannot use ref, out, or in parameter 'isCancelled' inside an anonymous method, lambda expression, query expression, or local function
我没有看到任何其他方法可以通过引用将 bool
放入事件处理程序。
- 我能得到的最接近的是这样的:
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
DoThis();
using (var tokenSource = new CancellationTokenSource()) {
var mytask = DoTheNewThingAsync(tokenSource.Token);
while (true)
{
//wait for either the task to finish, or 100ms
if (Task.WaitAny(mytask, Task.Delay(100)) == 0)
{
break; //mytask finished
}
if (isCancelled) tokenSource.Cancel();
}
// This will throw an exception if an exception happened in
// DoTheNewThingAsync. Otherwise we'd never know if it
// completed successfully or not.
mytask.GetAwaiter().GetResult();
}
DoThat();
}
}
但是,这会阻止调用者,所以我不完全明白这有什么用(如果被阻止,调用者如何更改 isCancelled
?)。但这就是您现有方法正在做的事情,所以也许它会起作用?
但这太hacky了。如果您完全可以控制上游如何完成任何事情,那就这样做。
关于c# - 是否可以将 `ref bool` 转换为 CancellationToken?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58661375/