构造函数中的事件处理程序 - 是可能的还是明智的?

时间:2010-08-04 12:50:56

标签: .net

我有一个对象可以从一瞬间到几分钟进行初始化。原因是构造函数从Web服务检索数据,可能是几千字节到几兆字节,并且根据用户的连接速度,性能可能会有很大差异。出于这个原因,我想把事件放在那将处理进度通知。

  

这是我的问题:我可以举办活动吗?   构造函数中的处理程序或应该   这种行为可以通过以下方式完成   加载方法?

例如:

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;
 }

} 

但是当我尝试将事件处理程序绑定到构造函数时,它们在被调用时始终为null:

MyObject o = new MyObject(1);
o.UpdateLoadProgress += new EventHandler<EventArgs>(o_UpdateLoadProgress);

我认为这是因为我在构造函数之后连接了事件。我看到的唯一选择是创建一个Load方法来完成构造函数的工作。缺点是任何使用此类的人必须知道在尝试访问Result(或任何其他属性)之前调用Load。

修改 这是最终的解决方案:

MyObjectBuilder类

public class MyObjectBuilder
    {
        public event ProgressChangedEventHandler ProgressChanged;

        public MyObject CreateMyObject()
        {
            MyObject o = new MyObject();
            o.Load(ProgressChanged);

            return o;
        }
    }

MyObject Class

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();                      
        }
    }

计划类

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);
        }
    }

2 个答案:

答案 0 :(得分:9)

另一种选择当然是将事件处理程序传递给构造函数。

我个人试图避免在构造函数中做这样的事情。创建新对象通常不应该启动后台任务IMO。您可能希望将其放入静态方法中 - 当然可以调用私有构造函数。

您还可以将您的班级拆分为两个 - 一个可以准备好所有内容的构建器(例如事件),然后是一个具有Result属性的“正在运行或已完成”的类。您可以在第一个类上调用Start或类似的东西来获取第二个类的实例。

答案 1 :(得分:1)

这可能吗?也许。这是明智的吗?否。

最明显的原因是,在对象构造之后,事件处理程序连接之前,不能保证后台线程不会执行。或者更糟糕的是,某些事件处理程序可能会被订阅,而其他事件处理程序则不会。