【问题标题】:Generic callbacks from C# Tasks来自 C# 任务的通用回调
【发布时间】:2013-12-27 09:43:14
【问题描述】:

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();
        }
    }
}

【问题讨论】:

  • 使用新的 async/await 非常容易处理异常。当您等待一个任务时,其中抛出的任何未处理的异常都会传播到等待者

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


【解决方案1】:

使用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");
        });

【讨论】:

    【解决方案2】:

    您可以使用IProgress&lt;T&gt; 接口或其Progress&lt;T&gt; implementation。你可以找到一篇描述其用法的博文here,但它基本上就像使用回调一样。

    像@Kirill Shlenskiy 建议的那样使用Reactive Extensions 也是一种选择,但我认为使用Tasks 向现有方法添加对此的支持可能不是最简单的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-04
      • 1970-01-01
      • 1970-01-01
      • 2014-04-25
      • 1970-01-01
      相关资源
      最近更新 更多