繁体   English   中英

实现AsyncCodeActivities(使用C#async / await)

[英]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. 哪种方法可以处理异常? 重新抛出? 将上下文设置为已取消?
  2. 是否有一种优雅的方式来编写现在可用的async / await语法?

谢谢

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM