[英]Implementing AsyncCodeActivities (using C# async/await)
很长一段时间我使用以下模板编写自定义AsyncCodeActivity类:
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);
}
}
我有一些问题:
谢谢
1)您应该从EndExecute
方法重新抛出异常。
2)我建议你创建自己的基本类型。 我在下面写了一个名为AsyncTaskCodeActivity<T>
:
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库,这个包装器变得更加简单:
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);
}
获得基本类型后,您可以定义自己的派生类型。 这是一个使用async
/ await
:
public sealed class MyActivity : AsyncTaskCodeActivity<int>
{
protected override async Task<int> ExecuteAsync(AsyncCodeActivityContext context)
{
await Task.Delay(100);
return 13;
}
}
这是一个将CPU绑定工作安排到线程池(类似于您当前的模板):
public sealed class MyCpuActivity : AsyncTaskCodeActivity<int>
{
protected override Task<int> ExecuteAsync(AsyncCodeActivityContext context)
{
return Task.Run(() => 13);
}
}
来自评论的更新:这是使用取消的。 我不是100%确定它是正确的,因为取消本身是异步的,并且AsyncCodeActivity<T>.Cancel
的语义AsyncCodeActivity<T>.Cancel
记录(即, Cancel
是否应该等待活动在取消状态下完成?是否可以接受?在调用Cancel
后成功完成的活动?)。
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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.