C#:显式地调用一个事件处理程序真是“一件好事”吗?

此问题与C#有关,但也可能适用于其他语言。 我预计不会使用以下代码:

using System.Windows.Forms; class MyForm : Form { private Timer myTimer; private Button myButton; public MyForm() { // Initialize the components, etc. myTimer.Tick += new EventHandler( myTimer_Tick ); myButton.Click += new EventHandler( myButton_Click ); myTimer.Start(); } private void myTimer_Tick( object sender, EventArgs eventArgs ) { myTimer.Stop(); // also, I see a lot of usage of // Timer.Enabled = true/false instead of -^ myButton_Click( this, ea /* or event EventArgs.Empty, or null */ ); return; } private void myButton_Click( object sender, EventArgs eventArgs ) { // do a lot of stuff, with lots of logic that doesn't even use the // state of the eventArgs return; } } 

我是一个人,因为上面的风格是我的宠儿? 还有其他人喜欢将事件处理与function工作量分离的清晰度,甚至将复杂的例程分离为单独的function吗?

甚至还有一种被接受的风格? 我觉得C#中的事件处理有任何表现力和灵活性可能会丢失这样的样式。 我觉得如果你的方法意味着“点击了一个按钮”,那么只有在点击一个按钮时才会调用它。

对于那些写这样的人,我会说:如果你坚持使用EventHandler方法来处理你的计时器滴答,然后点击你的按钮,那就把它叫做button_Click以外的东西 – 也许是“ handleUserEvent( object sender, EventArgs eventArgs ) ” 。

但实际上,问题是,是否有任何广泛使用的风格指南支持或阻止使用如上所述?

我同意Rex M的回答 ,但我会更进一步。 如果您正在使用MVC模式(或类似的东西),视图会将按钮单击委托给控制器。 控制器方法当然可以从你class级的其他地方调用 – 比如从你的计时器回调中调用。

那么,回到原始代码:

 using System.Windows.Forms; class MyForm : Form { private Timer myTimer; private Button myButton; private MyController myController; public MyForm() { // ... // Initialize the components, etc. // ... myTimer.Tick += new EventHandler( myTimer_Tick ); myButton.Click += new EventHandler( myButton_Click ); myTimer.Start(); } private void myTimer_Tick( object sender, EventArgs eventArgs ) { myTimer.Stop(); myController.SomeMethod() } private void myButton_Click( object sender, EventArgs eventArgs ) { // All the stuff done here will likely be moved // into MyController.SomeMethod() myController.SomeMethod(); } } 

使用MVC的一个优点是控制器与视图的分离。 控制器现在可以轻松地跨多种视图类型使用,并且退出GUI更容易维护,因为它们包含非常少的应用程序逻辑。

编辑:添加以回应OP的评论

软件工程的基本设计原则是关于耦合和内聚。 重要的是,我们努力最大限度地减少组件之间的耦合,同时最大化内聚力,因为这会导致更加模块化和可维护的系统。 像MVC这样的模式和Open / Closed Principal等主体构建在这些基础上,为开发人员提供了更加切实可行的实现模式。

因此,任何编写原始post中的代码的人都不了解软件设计的基础知识,需要大大提高他们的技能。 应该赞扬OP识别这种“代码味道”,并试图理解为什么它不太正确。

一些相关参考:

这绝对不是“个人偏好”。 对于如何编写结构良好,可维护,可重用且易于理解的代码,有一种清晰易懂的方法。 代码中的每个方法都应该封装一个可重用的function。 代码的结构应该是:

 void ButtonClickEventHandler(...) { UserData userData = //determine user data from event data DoUserThing(userData); } void DoUserThing(UserData userData) { //do stuff } void SomeOtherMethod() { UserData userData = //get userdata from some other source DoUserThing(userData); } 

(这是一个非常宽松的例子。在适当的应用程序中,所有内容都应该被关注分成不同的类 。)

如果你不需要传递eventargs, myButton.PerformClick()可能会更好一些。 有时您只想模拟一次点击。

但是,是的,我同意将真实代码转移到另一个函数更好。 我更喜欢我的事件处理程序非常简单 – 只需将UI连接到其他地方的逻辑。

然后,您可以重新排列和重新设计UI,而无需担心逻辑的位置。

如果另一个编码器在myButton_Click方法上工作,此代码会增加出现问题的机会。

如果我进入调整myButton.Click处理程序的实现怎么办? 我可以假设发送者对象是一个Button,并尝试强制转换:

 Button b = (Button)sender; 

我不知道没有阅读其余的类实现,我并不总是接收一个Button作为发送者。

所以我的观点是:-1的可维护性,因为打破了将作为myButton_Click参数传递的对象的假设。

简短的回答是,为什么要通过直接调用处理程序来模拟按钮单击? 如果要将两种方法连接到同一事件,则只需将其连接起来即可。 事件处理程序是多播委托,这意味着您可以添加多个委托。 不止一次地联系一个事件是完全可以接受的。

  myTimer.Tick += myTimer_Tick; myTimer.Tick += myButton_Click; myButton.Click += myButton_Click; 

这是否是WTF是我们无法通过短代码片段进行的工程调用。 但是,根据你的评论,它闻起来像WTF。 表单或任何UI都不应该处理业务逻辑。 它们需要在某种程度上具有业务逻辑意识(如在validation中),但它们本身并不封装/强制执行逻辑。

更进一步,遵循一些简单的实践作为基本的重构和使用分层(n层)的软件方法将带你走很长的路,你会意识到你提出的代码闻起来很糟糕。

最终你会遇到一些高级模式,比如MVC(模型 – 视图 – 控制器)和MVP(模型 – 视图 – 演示者),它们超越了简单的分层。 如果你遵循它们就可以很好地分离问题。

我同意接受的答案,但跳到’使用MVC’,这里有一些代码没有说明MVC,没有解释为什么对我来说有点货难。

关于C#中事件的特殊事情(和.Net框架一般是委托,它是函数指针的C / C ++等价物。附加到事件本身的方法在任何方面都不是特殊的,应该可以从任何地方调用。

更新:也许我应该更加冗长,但我认为我使用“应该”而不是“可以”或“可能”就足够了。 我的断言是,当需要它们实现的function时,应该调用事件处理程序,而不是让它们成为“执行工作”的方法的包装器,堆栈中调用的方法越少,就越好,特别是.Netexception处理的性能影响。