Should I use BackgroundWorker to implement an Event-based Asynchronous Pattern?
I have an assembly (.NET class library) that contains an object that implements EAP for asynchronous methods:
class Product
{
void Install();
void InstallAsync();
EventHandler<InstallProgressChangedEventArgs> Installing;
EventHandler<InstallCompletedEventArgs> Installed;
}
I am contemplating whether to use "standard" Thread
or use the BackgroundWorker
class provided by .NET.
I've read that one should only use BackgroundWorker
when it is e开发者_开发技巧xpected that the object will be used in "Windows Forms" or UI. The class library I'm writing can be used on Windows Form, WPF Application and Console application.
Also, if I am to use the BackgroundWorker
class, is it "proper" to not subclass from the BackgroundWorker
class? I don't want to expose the class' members as I will be providing my own events (Installing and Installed).
If the BackgroundWorker
class is not appropriate, what can you recommend and why?
There's no problems using the BW component outside of Windows forms UI applications. It's meant to be used where you just need to easily fire off a background thread and receive the callback when that work is complete.
If your only requirement is that you want to start up a thread to do work, and get results back, and you don't need the control you get by managing the thread yourself, I would recommend you use it.
I wouldn't subclass it though, unless you want your component to BE a background worker itself. That is, you're extending its behaviors. If you're simply using its behaviors there's no need to subclass, just use composition.
I recommend to use the ThreadPool:
ThreadPool.QeueuUserWorkItem((_state)=>{ this.OnInstalling( ... ); });
EDIT:
The using the ThreadPool instead of BackgroundWorker is "slimmer". The BackGroundWorker must create "big" instance encapsulating all the "multithreading stuff", but BuckgroundWorker in internals use Thread and/or ThreadPool (I don't remember which one).
Using ThreadPool instead of Thread is better for performance because when the action (sent to the ThreadPool) is done, the thread is reused for another actions in future. But creation new thread is "expensive" operation, reusing the thread is "cheap".
EDIT 2:
If you want raise event in paralel thread often the "nice" way is using the extension methods for that:
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); });
}
}
}
精彩评论