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
没有充分记录(即,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);
}