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);
}
}
来自 cmets 的更新:这是使用取消的一个。我不是 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);
}