C#类订阅自己发布的事件是不是很糟糕?

时间:2010-10-27 08:17:08

标签: c# events

我可能只是神经质,但我经常发现自己处于发布事件的类的情况下,我发现从类本身内部(例如在构造函数中)订阅此事件很方便,而不是只从外部订阅。

这对我来说听起来很合理,但我无法忍受这种拙劣的做法,因为我总是面对这样一个问题:“为什么不执行你提供的行动?触发事件的代码中的事件处理程序?“

public class Button
{
   public Button()
   {
      this.Click += someHandler; // bad practice?
   }

   public event EventHandler Click;

   public void HandleInput()
   {
      if (someInputCondition)
      {
         // Perform necessary actions here rather than 
         // subscribing in the constructor?
         this.Click(this, ...);
      }
   }
}

订阅自己的活动有什么缺点吗?

6 个答案:

答案 0 :(得分:8)

  

这对我来说听起来很合理,但我无法忍受这种拙劣的做法,因为我总是面对这样一个问题:“为什么不执行你提供的行动?触发事件的代码中的事件处理程序?“

要回答这个问题,请考虑部分类场景。假设您有一个基本类型B.您运行一个自动化工具,通过将其扩展到派生类D来装饰B.您的工具会生成一个分部类,以便使用D的开发人员可以根据自己的目的进一步自定义它。

在这种情况下,当D的机器生成的一方提出由B或D的机器生成的一方声明的事件时,D的用户创作的一方想要注册被调用似乎是完全合理的。

这是我们多年前设计VSTO时遇到的情景。事实证明,在C#中执行此操作并不困难,但要让它在VB中运行起来非常棘手。我相信VB已经对他们的事件订阅模型做了一些调整,以使这更容易。

那说:如果你能避免这种情况,我会的。如果您只是为内部订阅制作一个看似糟糕的代码味道的事件。 C#3中的部分方法在这里有很大帮助,因为它们使得机器生成的一方在用户生成的一方调用很少的通知功能变得容易且成本低,而不必去发布事件的麻烦。 / p>

答案 1 :(得分:5)

我认为没问题。但是如果你处理同一个类中的事件,你也可以覆盖事件方法:

protected override void OnClick(Eventargs e)
{
   base.OnClick(e);
}

这样效率更高,并且可以在必要时为您提供吞下事件的权力(只是不调用base.OnClick())。

答案 2 :(得分:2)

执行此操作时,由于内部优化,有一个非常exotic problem。由于优化,添加/删除事件处理程序不是线程安全的。它仅适用于声明类型使用的事件,如示例中所示。

幸运的是,这已经改变了4.0,但如果您使用的是旧版本,则可以体验到这一点。

答案 3 :(得分:1)

问题是“someHandler”会改变对象的状态。您是否希望在事件运行任何“外部”代码之前或之后更改此状态?

如果你订阅了这个事件,目前还不清楚状态的变化是什么,但是在“HandleInput()”中调用它会使它在被调用时更加清晰。

(调用“HandleInput()”,“OnClick”并将其设为虚拟更为正常,因此子类可以覆盖它)

说完上述内容后,订阅自己的活动通常没有太大的危害;在表示表单的UI类中,这是非常常见的,否则它会让很多读“你的代码的人感到惊讶”。

答案 4 :(得分:1)

如果您的按钮类应该是第一个接收click事件的按钮类,您应该在事件方法中编写代码,例如:

protected virtual void OnClick(EventArgs e)
{
    //insert your code here

    if(this.Click != null)
    {
        this.Click(this, e);
    }
}

但如果您的班级不是第一个接收者,您可以正常订阅该活动。

答案 5 :(得分:0)

如果你以普通的System.Windows.Form类为例,
 当您想要处理Form_Load事件(使用visual studio designer)时,它会被处理 在表格本身的类中!

this.Load += new System.EventHandler(this.Form1_Load);

 private void Form1_Load(object sender, EventArgs e)
 {
 }

所以我认为这根本不是问题!!。