如何编写像WebClient一样的异步类?
有没有什么方法可以使它更简短,并且不必为每个方法重复编写?
例如,我有:
Download(string a)
Download(string a, string b)
我需要为每个Async + Complete方法都重新编写吗?
非常感谢。
如何编写像WebClient一样的异步类?
有没有什么方法可以使它更简短,并且不必为每个方法重复编写?
例如,我有:
Download(string a)
Download(string a, string b)
我需要为每个Async + Complete方法都重新编写吗?
非常感谢。
这个示例是针对winforms的,我相信OP正在问有关asp.net的问题。一旦我从我的评论中得到一些反馈,我将修改我的答案。
你猜对了。我发现在.Net中多线程代码的一种优雅的方式是使用BackgroundWorker类。与在本机C++中实现线程相比,它真的非常简单。
实际上,MSDN页面上的示例可能有点令人不知所措,你可以总结如下(伪代码-可能无法编译):
private BackgroundWorker bw;
private void foobar() {
bw = new BackgroundWorker(); // should be called once, in ctor
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_Completed);
int i = 0;
bw.RunWorkerAsync(i);
}
private void bw_DoWork(object sender, DoWorkEventArgs e) {
int i = (int)e.Argument;
i++;
e.Result = i;
}
private void bw_Completed(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
MessageBox.Show(e.Error.Message);
} else {
int i = (int)e.Result;
MessageBox.Show(i.ToString());
}
}
关于最小化重复代码,你可以使用同一后台工作线程来处理所有方法,但是这可能会导致代码变得冗长而难以维护。如果只有几个方法,那么为每个操作创建事件处理程序不应该显得太杂乱。
BackgroundWorker
对于 Asp.Net
来说并不是很有用。我会更新我的答案,提供一个更合适的例子。 - Nick Bolton听起来你在询问实现一个类,该类公开具有异步版本方法的最佳实践,类似于WebClient的方式?
值得注意的是,在.NET框架中通常使用两种模式来支持异步使用的类。例如,您通常会看到像Stream这样的类,它们公开了BeginRead和EndRead。它们使用IAsyncResult并且往往更复杂。(MSDN上的概述)
然后稍后他们提出了基于事件的异步模式,例如WebClient使用的模式,其中您有一个DownloadString/DownloadStringAsync方法和相应的DownloadStringCompleted事件。对于简单情况,这更易于使用,但在我看来不如Begin/End模式灵活。
因此,在您的示例中,您有两个重载的方法。在这种情况下,我会简单地设计它们,使得具有较少参数的方法推迟到具有更多参数的方法,根据需要传递默认值或null。您可以有多个Download/DownloadAsync的重载,但只能有一个DownloadCompleted事件,这没问题。
这里是一个非常基本的实现。请注意,唯一真正执行任何工作的方法是同步下载方法。还要注意的是,这并不是最有效的方法。如果您想利用HttpWebRequest等异步IO功能,这个示例将很快变得复杂。还有一个过于复杂的异步操作模式,我从来没有喜欢过。class Downloader {
public void Download(string url, string localPath) {
if (localPath == null) {
localPath = Environment.CurrentDirectory;
}
// implement blocking download code
}
public void Download(string url) {
Download(url, null);
}
public void DownloadAsync(string url, string localPath) {
ThreadPool.QueueUserWorkItem( state => {
// call the sync version using your favorite
// threading api (threadpool, tasks, delegate.begininvoke, etc)
Download(url, localPath);
// synchronizationcontext lets us raise the event back on
// the UI thread without worrying about winforms vs wpf, etc
SynchronizationContext.Current.Post( OnDownloadCompleted, null );
});
}
public void DownloadAsync(string url) {
DownloadAsync(url, null);
}
private void OnDownloadCompleted(object state) {
var handler = DownloadCompleted;
if (handler != null) {
handler(this, EventArgs.Empty);
}
}
public event EventHandler DownloadCompleted;
}
asp.net
- 你是否计划从你的网站或服务中运行异步方法?如果是这样,我不确定这是否是你想要做的。但我可能错了...请详细解释一下,并告诉我们背景情况。 - Nick Bolton