我有自定义控件,我有接口这个控件暴露给它的用户。
public interface ILookupDataProvider
{
string IdColumnName { get; }
IEnumerable<IDataColumn> Metadata { get; set; }
void GetDataAsync(string parameters,
Action<IEnumerable<object>> onSuccess, Action<Exception> onError);
}
所以,我尝试在GetDataAsync
但我不知道如何在我的实现接口的类中实现此方法。我理解这部分,因为我有方法会执行,然后onCompletion
,onSucess
或onError
委托将被调用。
有人可以帮助学习如何编写这些语法吗?
编辑:
它是4.0,我不能使用await
命令
编辑2:
我使用DevForce框架来加载数据,但是为了这个示例 - 让我们以WCF服务为例。如何在我的接口实现中包装WCF服务调用?
另外,您认为创建这样的界面以呈现异步操作是否可以?例如,你会以不同的方式做事吗?
答案 0 :(得分:6)
这里的基本思想是查询将发生在后台线程中。操作完成后,您将使用onSuccess
和onError
回调来报告新值。例如
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);
}
答案 1 :(得分:3)
你真的不想使用这种模式:
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<T>
,您可以使用Result
property来获取结果(如果未完成任务,它将阻止),或者您可以使用ContinueWith
方法再次在异步操作完成时处理数据。
此外,您可以使用CancellationToken
structure参数实例来确定是否应取消操作:
Task<MyData> GetDataAsync(string parameters,
CancellationToken cancellationToken);
同样,ContinueWith
将允许您指明要取消的操作。
请注意,这是当前正在对Async CTP中使用await
和async
的方法进行建模的方式;他们正在返回Task
或Task<T>
;在您的代码中执行相同操作将允许您在烘焙这些语言功能时做好准备。
答案 2 :(得分: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" };
});
}