Tengo un objeto que puede tomar desde una fracción de segundo a un par de minutos para inicializar. La razón es que el constructor recupera datos de un servicio web que pueden ser de algunos kilobytes a varios megabytes, y dependiendo de la velocidad de conexión del usuario, el rendimiento puede variar mucho. Por esa razón, quiero poner eventos que manejarán la notificación de progreso.Controladores de eventos en constructores: ¿es posible o incluso sabio?
Aquí es mi pregunta: ¿Puedo poner eventos manipuladores en el constructor o debería este tipo de acción puede hacer con un método de carga ?
Por ejemplo:
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;
}
}
Sin embargo cuando intento para atar los controladores de eventos al constructor siempre son null cuando se llama:
MyObject o = new MyObject(1);
o.UpdateLoadProgress += new EventHandler<EventArgs>(o_UpdateLoadProgress);
Asumo que esto sucede porque el alambre hasta los eventos después del constructor. La única alternativa que veo es crear un método Load que haga el trabajo del constructor. La desventaja es que cualquiera que use esta clase debe saber para llamar a Load antes de intentar acceder a Result (o cualquier otra propiedad).
EDIT: Aquí está la solución final:
MyObjectBuilder Clase
public class MyObjectBuilder
{
public event ProgressChangedEventHandler ProgressChanged;
public MyObject CreateMyObject()
{
MyObject o = new MyObject();
o.Load(ProgressChanged);
return o;
}
}
MiObjeto clase del Programa de
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();
}
}
Clase
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);
}
}
En general, he descubierto que es una mala idea que un constructor cargue datos. Te arrepentirás tarde o temprano, y si haces pruebas unitarias, será "antes". –