Следует ли использовать BackgroundWorker для реализации асинхронного шаблона на основе событий? - PullRequest
2 голосов
/ 29 марта 2011

У меня есть сборка (библиотека классов .NET), которая содержит объект, который реализует EAP для асинхронных методов:

class Product
{
    void Install();
    void InstallAsync();
    EventHandler<InstallProgressChangedEventArgs> Installing;
    EventHandler<InstallCompletedEventArgs> Installed;
}

Я размышляю, использовать ли «стандартный» Thread или использовать BackgroundWorker класс, предоставленный .NET.

Я прочитал , что следует использовать BackgroundWorker только тогда, когда ожидается, что объект будет использоваться в «Windows Forms» или пользовательском интерфейсе.Библиотеку классов, которую я пишу, можно использовать в Windows Form, WPF Application и Console application.

Кроме того, если я хочу использовать класс BackgroundWorker, это "правильно" для not подкласс класса BackgroundWorker?Я не хочу показывать участников класса, поскольку я буду предоставлять свои собственные события (Установка и установка).

Если класс BackgroundWorker не подходит, что вы можете порекомендовать и почему?

Ответы [ 2 ]

4 голосов
/ 29 марта 2011

Нет проблем с использованием компонента BW вне приложений пользовательского интерфейса форм Windows. Он предназначен для использования там, где вам просто нужно легко запустить фоновый поток и получить обратный вызов, когда эта работа будет завершена.

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

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

1 голос
/ 29 марта 2011

Рекомендую использовать ThreadPool:

ThreadPool.QeueuUserWorkItem((_state)=>{ this.OnInstalling( ... ); });

EDIT:

Использование ThreadPool вместо BackgroundWorker "тоньше". BackGroundWorker должен создавать «большой» экземпляр, инкапсулирующий все «многопоточность», но BuckgroundWorker во внутренних компонентах использует Thread и / или ThreadPool (я не помню, какой именно).

Использование ThreadPool вместо Thread лучше для производительности, потому что когда действие (отправленное в ThreadPool) выполнено, поток повторно используется для других действий в будущем. Но создание нового потока - «дорогая» операция, повторное использование потока - «дешевый».

РЕДАКТИРОВАТЬ 2:

Если вы хотите поднять событие в параллельном потоке, часто «хороший» способ - использовать для этого методы расширения:

class Product {
    public void Install() {
        this.OnInstalling( ... );
        ...
        this.OnInstalled( ... );
    }
    public void InstallAsync() {
        this.OnInstallingAsync( ... );
        ...
        this.OnInstalledAsync( ... );
    }

    protected virtual void OnInstalling( InstallProgressChangedEventArgs e ) {
        this.Installing.Raise(this, e);
    }
    protected virtual void OnInstallingAsync( InstallProgressChangedEventArgs e ) {
        this.Installing.RaiseAsync(this, e);
    }
    public event EventHandler<InstallProgressChangedEventArgs> Installing;

    protected virtual void OnInstalled( InstallCompletedEventArgs e ) {
        this.Installed.Raise(this, e);
    }
    protected virtual void OnInstalledAsync( InstallCompletedEventArgs e ) {
        this.Installed.RaiseAsync(this, e);
    }
    public event EventHandler<InstallCompletedEventArgs> Installed;
}
// ...
public static class EventExtensions {
    public static void Raise( this EventHandler handler, object sender, EventArgs e ) {
        if (null != handler) { handler(sender, e); }
    }

    public static void Raise<TEventArgs>( this EventHandler<TEventArgs> handler, object sender, TEventArgs e ) where TEventArgs : EventArgs {
        if (null != handler) { handler(sender, e); }
    }

    public static void RaiseAsync( this EventHandler handler, object sender, EventArgs e ) {
        if (null != handler) {
            ThreadPool.QeueuUserWorkItem((_state)=>{ handler(sender, e); });
        }
    }

    public static void RaiseAsync<TEventArgs>( this EventHandler<TEventArgs> handler, object sender, TEventArgs e ) where TEventArgs : EventArgs {
        if (null != handler) {
            ThreadPool.QeueuUserWorkItem((_state)=>{ handler(sender, e); });
        }
    }
}
...