Как мне написать асинхронный класс с минимальным количеством повторяющегося кода? - PullRequest
3 голосов
/ 11 января 2010

как мне написать асинхронный класс, такой как WebClient?

Есть ли в любом случае, я могу сделать это коротким и не нужно повторять это для каждого метода?

например, у меня есть:

Download(string a)
Download(string a, string b)

мне нужно переписать метод Async + Complete для каждого из них?

Большое спасибо.

Ответы [ 4 ]

3 голосов
/ 11 января 2010

Обновление:

Этот пример для 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());
  }
}

Что касается минимизации повторяющегося кода, вы можете использовать один и тот же фоновый рабочий для всех методов, как я полагаю, но вы можете отправиться на вонючую область кода с большим блестящим золотым молотком. Если у вас есть только несколько методов, то создание обработчиков событий для каждой операции не должно выглядеть слишком грязно.

1 голос
/ 16 января 2010

Похоже, вы спрашиваете о передовых методах реализации класса, который предоставляет методы, которые имеют асинхронные версии, аналогичные тем, что делает WebClient?

Стоит отметить, что в .NET Framework обычно используются два шаблона для классов, поддерживающих асинхронное использование. Например, вы обычно видите классы, такие как Stream, которые предоставляют BeginRead и EndRead. Они используют IAsyncResult и, как правило, более сложны в использовании. ( Обзор на MSDN )

Позже они придумали основанный на событиях асинхронный шаблон , такой как тот, который используется WebClient, где у вас есть метод DownloadString / DownloadStringAsync и соответствующее событие DownloadStringCompleted. С этим проще работать в простых случаях, но, на мой взгляд, он не такой гибкий, как шаблон «Начало / Конец».

Итак, в вашем примере у вас есть два перегруженных метода. В этом случае я просто разработал бы их так, чтобы метод с меньшим количеством параметров относился к методу с большим количеством параметров, передавая значения по умолчанию или нули при необходимости. У вас может быть несколько перегрузок Download / DownloadAsync, но у вас может быть только одно событие DownloadCompleted, и это нормально.

Вот очень простая реализация. Обратите внимание, что единственный метод, который действительно выполняет какую-либо работу, - это один синхронный метод Download. Также важно отметить, что это также не самый эффективный способ сделать это. Если вы хотите воспользоваться возможностями асинхронного ввода-вывода HttpWebRequest и тому подобным, этот пример быстро усложнится. Существует также слишком сложный шаблон Async Operation , который мне никогда не нравился.

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;

}
1 голос
/ 14 января 2010

Если вы хотите вызвать ваш синхронный метод асинхронно, вам нужно будет использовать делегатов. http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx. При таком подходе вам не нужно создавать методы Async и Complete.

Шаблон, который вы описываете, заключается в использовании IAsyncResult, и в этом случае вам необходимо будет реализовать IAsyncResult (вы также можете использовать тот, что в Framework, в зависимости от ваших требований). Получите это в своем классе и реализуйте методы Async и Complete, как вы упомянули.

0 голосов
/ 15 января 2010

Используйте MethodInvoker.BeginInvoke для вызова нового thead.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...