TaskCompletionSource 用法
TaskCompletionSource usage
如果取消完成源,我会在结果变量中收到什么?
async void SomeMethod()
{
.....
Run();
var result = await GetResult();
.....
}
Task<SomeResult> GetResult()
{
return myCompletionSource.Task;
}
TaskCompletionSource myCompletionSource;
void Run()
{
myCompletionSource= new TaskCompletionSource();
TriggerSomeLongLastingLogicWhichWillCallCallBackBelow();
}
void SomeCallback()
{
if (someCondition)
{
myCompletionSource.SetResult(<someResult>);
}
else
{
myCompletionSource.SetCancelled();
}
}
我不太确定这种做法是否正确。
- 换句话说,依赖任务状态而不是使用状态变量为 "someresult" 创建包装器是一个好习惯吗?
- 如何处理取消的任务?我不喜欢回调,也不喜欢 ContinueWith 的解决方案,我可以在其中分析任务状态。
What would I receive in result variable if completion source was cancelled?
您的代码在等待已取消的任务时将抛出 OperationCancelledException
。所以永远不会设置结果变量。
您可以使用 try/catch
块处理异常:
async Task SomeMethod()
{
try
{
.....
Run();
var result = await GetResult();
}
catch(OperationCancelledException)
{
// handle cancelled operation
}
}
此外,SomeMethod
应该 return a Task
因为 void
returning async
方法通常只适用于事件处理程序,因为他们必须 return void
。我在博客上简要介绍了它 here。
一般来说,如果您希望某个操作可取消,您可以传入一个 CancellationToken
,该操作必须检查该操作并将其传递给它启动的其他操作。所以你把它一直传递到链下并进入你的回调。
您还可以使用 CancellationToken
注册一个回调,在令牌被取消时取消 TaskCompletionSource
,这样您就不需要在您的方法中执行它。
void Run()
{
var cts = new CancellationTokenSource();
var myCompletionSource= new TaskCompletionSource();
cts.Token.Register(() => myCompletionSource.SetCancelled());
TriggerSomeLongLastingLogicWhichWillCallCallBackBelow(cts.Token);
}
void SomeCallback(CancellationToken token)
{
// do some work
....
token.ThrowIfCancellationRequested();
if (someCondition)
{
myCompletionSource.SetResult(<someResult>);
}
else
{
myCompletionSource.SetException(new Exception("error occcured"));
}
}
如果取消完成源,我会在结果变量中收到什么?
async void SomeMethod()
{
.....
Run();
var result = await GetResult();
.....
}
Task<SomeResult> GetResult()
{
return myCompletionSource.Task;
}
TaskCompletionSource myCompletionSource;
void Run()
{
myCompletionSource= new TaskCompletionSource();
TriggerSomeLongLastingLogicWhichWillCallCallBackBelow();
}
void SomeCallback()
{
if (someCondition)
{
myCompletionSource.SetResult(<someResult>);
}
else
{
myCompletionSource.SetCancelled();
}
}
我不太确定这种做法是否正确。
- 换句话说,依赖任务状态而不是使用状态变量为 "someresult" 创建包装器是一个好习惯吗?
- 如何处理取消的任务?我不喜欢回调,也不喜欢 ContinueWith 的解决方案,我可以在其中分析任务状态。
What would I receive in result variable if completion source was cancelled?
您的代码在等待已取消的任务时将抛出 OperationCancelledException
。所以永远不会设置结果变量。
您可以使用 try/catch
块处理异常:
async Task SomeMethod()
{
try
{
.....
Run();
var result = await GetResult();
}
catch(OperationCancelledException)
{
// handle cancelled operation
}
}
此外,SomeMethod
应该 return a Task
因为 void
returning async
方法通常只适用于事件处理程序,因为他们必须 return void
。我在博客上简要介绍了它 here。
一般来说,如果您希望某个操作可取消,您可以传入一个 CancellationToken
,该操作必须检查该操作并将其传递给它启动的其他操作。所以你把它一直传递到链下并进入你的回调。
您还可以使用 CancellationToken
注册一个回调,在令牌被取消时取消 TaskCompletionSource
,这样您就不需要在您的方法中执行它。
void Run()
{
var cts = new CancellationTokenSource();
var myCompletionSource= new TaskCompletionSource();
cts.Token.Register(() => myCompletionSource.SetCancelled());
TriggerSomeLongLastingLogicWhichWillCallCallBackBelow(cts.Token);
}
void SomeCallback(CancellationToken token)
{
// do some work
....
token.ThrowIfCancellationRequested();
if (someCondition)
{
myCompletionSource.SetResult(<someResult>);
}
else
{
myCompletionSource.SetException(new Exception("error occcured"));
}
}