实现异步codeActivities(使用C#异步/等待) [英] Implementing AsyncCodeActivities (using C# async/await)
问题描述
由于很长一段时间我写在使用以下模板的自定义异步codeActivity类:
Since long time I'm writing custom AsyncCodeActivity classes using the following template:
public sealed class MyActivity : AsyncCodeActivity<T>
{
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var task = new Task<T>(this.Execute, state, CancellationToken.None, TaskCreationOptions.AttachedToParent);
task.ContinueWith(s => callback(s));
task.Start();
return task;
}
protected override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
var task = result as Task<T>;
if (task.Exception != null)
{
// Error handling. Rethrow? Cancel?
}
return task.Result;
}
private T Execute(object state)
{
// Logic here
return default(T);
}
}
我有一些关于它的问题:
I have some questions about it:
- 这是处理异常的正确方法?重新抛出?设置上下文取消?
- 有没有把它与异步/的await语法现已? 写一种优雅的方式
- Which is the right way to handle exceptions? Rethrowing? Setting the context as canceled?
- Is there an elegant way to write it with async/await syntax available now?
感谢
推荐答案
1)你应该重新抛出从 EndExecute
法的例外。
1) You should rethrow the exception from your EndExecute
method.
2)我建议你创建你自己的基本类型。我写了一上来名为的AsyncTask codeActivity&LT; T&GT;
如下:
2) I recommend you create your own base type. I wrote one up called AsyncTaskCodeActivity<T>
below:
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>
{
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var task = ExecuteAsync(context);
var tcs = new TaskCompletionSource<T>(state);
task.ContinueWith(t =>
{
if (t.IsFaulted)
tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(t.Result);
if (callback != null)
callback(tcs.Task);
});
return tcs.Task;
}
protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
var task = (Task<T>)result;
try
{
return task.Result;
}
catch (AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
throw;
}
}
protected abstract Task<T> ExecuteAsync(AsyncCodeActivityContext context);
}
如果你用我的 AsyncEx 库,该包装变得简单多了:
If you use my AsyncEx library, this wrapper becomes much simpler:
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>
{
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var task = ExecuteAsync(context);
return AsyncFactory<T>.ToBegin(task, callback, state);
}
protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
return AsyncFactory<T>.ToEnd(result);
}
protected abstract Task<T> ExecuteAsync(AsyncCodeActivityContext context);
}
一旦你的基本类型,你可以定义自己的派生类型。下面是一个使用异步
/ 等待
:
public sealed class MyActivity : AsyncTaskCodeActivity<int>
{
protected override async Task<int> ExecuteAsync(AsyncCodeActivityContext context)
{
await Task.Delay(100);
return 13;
}
}
而这里的一个调度CPU绑定的工作线程池(类似于当前模板):
And here's one that schedules CPU-bound work to the thread pool (similar to your current template):
public sealed class MyCpuActivity : AsyncTaskCodeActivity<int>
{
protected override Task<int> ExecuteAsync(AsyncCodeActivityContext context)
{
return Task.Run(() => 13);
}
}
从评论更新:下面是一个使用取消。我不是100%肯定它是正确的,因为取消本身是异步的,并且语义异步codeActivity&LT; T&GT; .Cancel
的underdocumented(即是取消
应该等待活动取消状态来完成吗?它是可以接受的一项活动后,取消
被称为?)。
Update from comments: Here's one that uses cancellation. I'm not 100% sure it's correct, because cancellation is itself asynchronous, and the semantics for AsyncCodeActivity<T>.Cancel
are underdocumented (i.e., Is Cancel
supposed to wait for the activity to complete in a canceled state? Is it acceptable for an activity to complete successfully after Cancel
is called?).
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>
{
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
var cts = new CancellationTokenSource();
context.UserState = cts;
var task = ExecuteAsync(context, cts.Token);
return AsyncFactory<T>.ToBegin(task, callback, state);
}
protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
try
{
return AsyncFactory<T>.ToEnd(result);
}
catch (OperationCanceledException)
{
if (context.IsCancellationRequested)
context.MarkCanceled();
else
throw;
return default(T); // or throw?
}
}
protected override void Cancel(AsyncCodeActivityContext context)
{
var cts = (CancellationTokenSource)context.UserState;
cts.Cancel();
}
protected abstract Task<T> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken);
}
这篇关于实现异步codeActivities(使用C#异步/等待)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!