4

我有自定义控件,并且我有这个控件向其用户公开的界面。

public interface ILookupDataProvider
{
    string IdColumnName { get; }

    IEnumerable<IDataColumn> Metadata { get; set; }

    void GetDataAsync(string parameters, 
        Action<IEnumerable<object>> onSuccess, Action<Exception> onError);
}

所以,这是我尝试在GetDataAsync

但是我不知道如何在实现接口的类中实现这个方法。我理解这部分,因为我有方法将执行然后onCompletiononSucess或者onError委托将被调用。

有人可以帮助您了解如何编写这些语法吗?

编辑:

它是 4.0,我不能使用await命令

编辑2:

我使用 DevForce 框架来加载数据,但为了这个示例 - 让我们以 WCF 服务为例。如何在我的接口实现中包装 WCF 服务调用?

另外,您认为创建这样的界面来呈现异步操作是否可以?例如,您会对事件采取不同的做法吗?

4

3 回答 3

6

这里的基本思想是查询将在后台线程中发生。操作完成后,您将使用onSuccessonError回调来报告新值。例如

void GetDataAsync(
  string parameters, 
  Action<IEnumerable<object>> onSuccess, 
  Action<Exception> onError) {

  WaitCallback doWork = delegate { 
    try { 
      IEnumerable<object> enumerable = GetTheData(parameters);
      onSuccess(enumerable);
    } catch (Exception ex) {
      onError(ex);
    }
  };

  ThreadPool.QueueUserWorkItem(doWork, null);
}
于 2011-11-07T21:07:26.470 回答
3

你真的不想使用这种模式:

void GetDataAsync(string parameters, 
    Action<IEnumerable<object>> onSuccess, Action<Exception> onError);

相反,你想使用这个:

Task GetDataAsync(string parameters);

在返回 aTask时,您将返回一个代表异步工作单元的实例。从那里,API 的使用者可以选择调用ContinueWith并决定当它成功或出现错误时要做什么。

但是,您的示例中存在设计缺陷。在名为 的方法GetDataAsync中,我希望返回数据。这不是问题,您只需将签名更改为:

Task<MyData> GetDataAsync(string parameters);

这现在返回一个Task<T>您可以使用的Result属性来获取结果(如果任务没有完成,它将阻塞),或者您可以ContinueWith在异步操作完成时再次使用该方法来处理数据。

此外,您可以采用参数的CancellationToken结构实例来确定是否应该取消操作:

Task<MyData> GetDataAsync(string parameters, 
    CancellationToken cancellationToken);

再次,ContinueWith将允许您指示取消操作。

请注意,这是当前对使用Async CTPawaitasyncAsync CTP中的方法进行建模的方式;他们正在返回TaskTask<T>;在你的代码中做同样的事情会让你在这些语言特性被烘焙时做好准备。

于 2011-11-07T21:14:48.793 回答
1

要使用任务,您可以像这样使用它。要记住的唯一棘手的事情是在 UI 线程中执行回调,这是使用 TaskScheduler.FromCurrentSynchronizationContext() 实现的,因此您可以更新 UI 或在出现问题时显示消息框。

由于这些东西的事件驱动性质,如果您按下启动 WCF 调用的按钮,您可能会得到结果,而不是按照您发送请求的顺序返回。如果要开始新操作,可以通过存储已启动的任务并取消上次启动的任务来防止这种情况,或者您可以在任务运行时简单地忽略后续请求。

private void button1_Click(object sender, EventArgs e)
{
    GetDataAsync("www.data.com").ContinueWith(result =>
        {
            if (result.Exception != null)
            {
                MessageBox.Show(this, "Error: {0}" + result.Exception, "Error");
            }
            else
            {
                foreach (var obj in result.Result)
                {
                    textBox1.Text += obj.ToString();
                }
            }
        },
        TaskScheduler.FromCurrentSynchronizationContext()
        );

}

Task<IEnumerable<object>> GetDataAsync(string parameters)
{
    return Task<IEnumerable<object>>.Factory.StartNew(() =>
    {
        Thread.Sleep(500);
      //  throw new ArgumentException("uups");
        // make wcf call here
        return new object[] { "First", "second" };
    });
}
于 2011-11-07T21:43:02.183 回答