【问题标题】:Need to wrap my head around Async operations需要了解异步操作
【发布时间】:2011-12-23 22:57:41
【问题描述】:

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

public interface ILookupDataProvider
{
    string IdColumnName { get; }

    IEnumerable<IDataColumn> Metadata { get; set; }

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

所以,我尝试在 GetDataAsync 中公开异步操作

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

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

编辑:

现在是 4.0,我不能使用 await 命令

编辑 2:

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

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

【问题讨论】:

  • 你是在使用 async/await 之后还是你想知道什么?
  • 您的目标是 .NET 3.5 还是 .NET 4
  • 我不能使用异步等待,因为我们正在使用 VS2010 进行生产我想为这个接口编写实现并且无法弄清楚语法。即使是简单的非异步实现也应该可以帮助我理解如何针对 Action 进行编码
  • 这取决于GetDataAsync 的作用。它是从磁盘读取的吗?拨打 WCF 电话?查询数据库?无论它调用什么,都可能有一个异步 API,您将根据该 API 实现 GetDataAsync。为了帮助您,我们需要知道您将使用哪个 API。
  • @Joe 我编辑了主要帖子以提供有关我所做工作的更多详细信息。

标签: c# silverlight asynchronous devforce


【解决方案1】:

这里的基本思想是查询将在后台线程中发生。操作完成后,您将使用 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);
}

【讨论】:

  • 不知道为什么不使用TaskTask&lt;T&gt;,这些类的全部意义在于将异步操作完成通知的控制推送到逻辑之外方法。
【解决方案2】:

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

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

相反,你想使用这个:

Task GetDataAsync(string parameters);

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

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

Task<MyData> GetDataAsync(string parameters);

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

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

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

同样,ContinueWith 将允许您指明取消时要采取的操作。

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

【讨论】:

  • 我觉得你是对的,但是你的例子更复杂,让我无法理解:) 我知道我必须这样做,但仍然。我认为我不能使用它,除非你告诉我如何在实现接口的类中实现它,例如将 WCF 调用包装到其中。我不关心取消和继续操作。我只需要知道它何时以异常或数据结束
  • 好的,这在 Silverlight 中可用吗?我认为任务不可用
【解决方案3】:

要使用任务,您可以像这样使用它。要记住的唯一棘手的事情是在 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" };
    });
}

【讨论】:

  • 很遗憾我无法在 Silverlight 4 中使用任务
猜你喜欢
  • 2013-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 2013-01-17
  • 2023-03-16
  • 2011-07-14
  • 1970-01-01
相关资源
最近更新 更多