Ich habe ein Objekt, das von einem Bruchteil einer Sekunde bis zu ein paar Minuten dauern kann, um zu initialisieren. Der Grund dafür ist, dass der Konstruktor Daten von einem Webservice abfragt, die einige Kilobyte bis einige Megabyte betragen können, und abhängig von der Verbindungsgeschwindigkeit des Benutzers kann die Leistung stark variieren. Aus diesem Grund möchte ich Ereignisse in die Fortschrittsbenachrichtigung einfügen.Event Handlers in Konstruktoren - ist es möglich oder sogar klug?
Hier ist meine Frage: Kann ich Handler im Konstruktor Ereignis setzen oder sollte diese Art der Aktion mit einer Load-Methode durchgeführt werden?
Zum Beispiel:
public class MyObject
{
public event EventHandler<UpdateLoadProgressEventArgs> UpdateLoadProgress;
public MyObject(int id)
{
Background worker bgWorker = new BackgroundWorker();
bgWorker.DoWork += delegate(object s, DoWorkEventArgs args)
{
//load data and update progress incrementally
UpdateLoadProgress(this, new UpadteLoadProgressEventArgs(progressValue));
Result = someValue;
}
bgWorker.RunWorkAsync();
}
public int Result
{
get;
set;
}
}
aber wenn ich versuche, die Event-Handler an den Konstruktor zu binden sie sind immer null, wenn sie aufgerufen werden:
MyObject o = new MyObject(1);
o.UpdateLoadProgress += new EventHandler<EventArgs>(o_UpdateLoadProgress);
Ich nehme an, dies geschieht, weil ich Draht up die Ereignisse nach dem Konstruktor. Die einzige Alternative, die ich sehe, ist das Erstellen einer Load-Methode, die die Arbeit des Konstruktors ausführt. Der Nachteil ist, dass jeder, der diese Klasse verwendet, Load aufrufen muss, bevor er auf Result (oder eine andere Eigenschaft) zugreifen kann.
EDIT: Hier ist die endgültige Lösung:
MyObjectBuilder Klasse
public class MyObjectBuilder
{
public event ProgressChangedEventHandler ProgressChanged;
public MyObject CreateMyObject()
{
MyObject o = new MyObject();
o.Load(ProgressChanged);
return o;
}
}
MyObject Klasse
public class MyObject
{
public int Result { get; set;}
public void Load(ProgressChangedEventHandler handler)
{
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.WorkerReportsProgress = true;
bgWorker.ProgressChanged += handler;
bgWorker.DoWork += delegate(object s, DoWorkEventArgs args)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(10);
Result = i;
bgWorker.ReportProgress(i);
}
};
bgWorker.RunWorkerAsync();
}
}
Programm Klasse
class Program
{
static void Main(string[] args)
{
MyObjectBuilder builder = new MyObjectBuilder();
builder.ProgressChanged += new ProgressChangedEventHandler(builder_ProgressChanged);
MyObject o = builder.CreateMyObject();
Console.ReadLine();
}
static void builder_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine(e.ProgressPercentage);
}
}
Ich habe im Allgemeinen festgestellt, dass es eine schlechte Idee für einen Konstruktor ist, Daten zu laden. Sie werden es früher oder später bereuen - und wenn Sie Komponententests durchführen, wird es "früher" sein. –