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

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

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

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

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

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

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

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

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

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

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

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

这样更有效,并且如果需要,您可以吞下事件(简单地不调用base.OnClick())。

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

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

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

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

(同样调用“HandleInput()”,“OnClick”并使其成为虚拟更常见,因此子类可以覆盖它)

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

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

 protected virtual void OnClick(EventArgs e) { //insert your code here if(this.Click != null) { this.Click(this, e); } } 

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

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

 this.Load += new System.EventHandler(this.Form1_Load); private void Form1_Load(object sender, EventArgs e) { } 

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