来自C#任务的通用回调

时间:2013-12-27 09:43:14

标签: c# callback task-parallel-library async-await

async Task调用通用回调的推荐方法是什么?例如,进度,异常处理和完成(但可能是其他状态)。

以下代码显示了实现它的一种方法,但感觉应该有一种更清晰的方法来处理它。 (FWIW我已经看到很多使用ContinueWith作为完成回调的例子,但这并不真正处理其他情况,如进度和异常处理。)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Testcode
{
    class TestApp
    {
        public static void Main()
        {
            AsyncCallbackTest test = new AsyncCallbackTest();
            test.RunTest();
        }
    }

    interface ICallback
    {
        void onProgress(String status);
        void onCompleted();
        void onFaulted(Exception e);
    }

    class AsyncCallbackTest : ICallback
    {

        public void RunTest()
        {
            //run task in background
            Task task = new Task(new Action<Object>(ExampleTask), this);
            task.Start();

            //do something else here
            //...

            //wait for task completion
            task.Wait();
        }

        public void onProgress(string status)
        {
            Console.Out.WriteLine(status);
        }

        public void onCompleted()
        {
            Console.Out.WriteLine("COMPLETED");
        }

        public void onFaulted(Exception e)
        {
            Console.Out.WriteLine("EXCEPTION: " + e.Message);
        }

        private void ExampleTask(object ocb)
        {
            ICallback callback = ocb as ICallback;

            //do some work
            try
            {
                DoSomething(callback);
            }
            catch (Exception e)
            {
                //how to pass exceptions/errors?
                callback.onFaulted(e);
            }
        }

        //example long-running task
        private void DoSomething(ICallback callback)
        {
            callback.onProgress("Starting");
            Thread.Sleep(5000);
            callback.onProgress("Step 1 complete");
            Thread.Sleep(5000);
            callback.onProgress("Step 2 complete");
            Thread.Sleep(5000);
            callback.onCompleted();
        }
    }
}

2 个答案:

答案 0 :(得分:4)

async - await非常容易完成和处理异常。进度处理正是IProgress接口的用途。

因此,您的方法的签名将类似于:

public Task DoSomething(IProgress<string> progress = null);

你会这样称呼它:

try
{
    await DoSomething(new Progress<string>(status => Console.WriteLine(status)));
    Console.WriteLine("COMPLETED");
}
catch (Exception e)
{
    Console.WriteLine("EXCEPTION: " + e.Message);
}

如果你不能使用C#5.0,那么你可以使用ContinueWith()代替await而你必须自己编写IProgressProgress

DoSomething(new Progress<string>(status => Console.WriteLine(status)))
    .ContinueWith(t =>
        {
            if (t.Exception != null)
                Console.WriteLine("EXCEPTION: " + t.Exception.InnerException.Message);
            else
                Console.WriteLine("COMPLETED");
        });

答案 1 :(得分:3)

您可以使用IProgress<T>界面或其Progress<T> implementation。您可以找到描述其用法here的博客文章,但它基本上就像使用回调一样。

使用类似@Kirill Shlenskiy的Reactive Extensions也可以选择,但我认为使用Tasks添加对现有方法的支持可能不是最简单的解决方案。