活动订阅。最佳实践:自动(VS)还是手动(明确编码)? [英] Event subscription. Best practice: automatic (VS) or manual (explicitly coded)?

查看:49
本文介绍了活动订阅。最佳实践:自动(VS)还是手动(明确编码)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

示例将说明我的意思。



带有确定按钮的WinForms应用程序以及单击时执行的代码。



选择#1。双击IDE中的按钮以在表单类中创建存根。



选择#2。在表单构造函数中使用显式lambda表达式,如下所示:

 okButton.Click + =(s,e)= > ;  okButton_Click(); 



我倾向于#2,理由是它显示连接而无需查看属性窗口中的事件对于那个控制。



两种方式都不是什么大问题,但我想知道是否有一个更好的选择。

解决方案

首先,我认为你很努力地研究创建EventHandler的所有可能形式,并将它们连接到各种控制事件上。



对于EventHandler的简单使用,我看到让Visual Studio通过双击Control或在属性浏览器中为控件选择一个事件来为程序员创建存根有很多好处。这是一种便利功能,可以提高您的工作效率,并封装简单的逻辑关系,因此您可以专注于手头的大规模任务。



没有使用这种内置功能的性能惩罚,如果你是强迫性的,你可能会收到一些新的担心,如果语法困扰你:)



当您执行更复杂的操作时,会出现在代码中创建自己的EventHandler(使用Lambda表达式,匿名方法)的有机原因。显然,如果您定义自己的事件,则必须定义自己的EventHandler才能使用这些事件,但是,让我们考虑一些您想要定义自己的EventHandler的其他情况:



1.如果要直接操作.NET事件是一个多播委托的事实,该委托维护可能的EventHandler队列,所有这些都将被执行。通过操纵我的意思是删除现有的EventHandler,添加一个EventHandler,恢复以前删除的EventHandler等等。



2.与#1一样,但有规定您希望直接操作 order ,其中EventHandlers在Event内部队列中执行。



3.在复杂控制情况下你在哪里可能想存储EventHandlers。例如,想象一下Dictionary< TreeNode,CustomEvent>您可能希望基于TreeNode执行不同的代码。或者,想象一下状态机类型的UI,对于每个状态,您需要为每个状态的UI中的某些控件分配不同的EventHandler。



将代表作为值存储在字典中的示例可以在我关于DevX的文章中找到:[ ^ ]。你可以用完全相同的方式存储EventHandler。



场景#2是我正在处理的项目中我正在处理的那个,我已经解决了它通过在静态类中创建Type Action的静态属性:在不同的情况下,不同的FormHandler通过各种Forms分配给该属性,并且重新构造响应于某个UI事件的EventHandler的执行顺序。听起来比它更具异国情调。



这种类型的解决方案允许我执行在各种外部对象(Forms)中定义的EventHandler,而且没有特定的紧耦合。 static Class和Forms,当然,由于EventHandler定义是Form的内部,它可以访问Form的所有私有/公共字段,方法等,而静态类则不能。

实际上,这些并不是两种不同的选择。我同意你的担忧,因为我一直非常不喜欢某些语言和技术(VB 6就是一个很好的例子,VBA是一个更糟糕的罪犯),这种隐藏的魔法涉及多少事情。



但是在这里你会发现,在任何情况下都没有神奇的自动订阅,尽管它可能看起来像这样。当您在Visual Studio中创建表单时,让我们说MainForm,如果仔细观察,您会注意到表单类分布在两个文件MainForm.cs和MainForm.Designer.cs之间,每个文件都以partial class MainForm意味着它们都贡献了代码,这些代码被拼凑在一起以编译成单个类。 MainForm.cs通常包含您手动添加的所有内容(尽管如果您出于某种原因可以创建更多有助于同一类的文件)。但是整个表单的其余部分 - 布局,事件订阅,一切 - 仍然使用常规的旧C#代码完成,您可以在MainForm.Designer.cs中找到它。 IDE中的图形编辑器只是在进行C#代码生成,而不是隐藏任何你无法看到的秘密。



所以双击之后如果你在名为InitializeComponent()的方法中查看.Designer.cs文件中的那个按钮来自动创建一个事件处理程序,我想你会看到一条看起来非常像你的选择#2的行。虽然它可能不是使用完全相同的语法(这里实际上不需要lambda)。



我个人认为最好将所有这些初始化放入大部分时间都是一个地方,所以基本上我会说在应用程序中保持一致。如果您打算使用Visual Studio之外的其他工具进行开发,那么在不使用VS图形设计器的情况下创建表单(例如,您可以在文本编辑器中完成所有这些工作,而不需要任何图形设计器),或者如果您要在表单初始化完成后动态地主动订阅和取消订阅事件,那么您可能有充分的理由将这些放在其他地方,但在很多或大多数情况下,我不明白为什么使用设计师插入这些是一个问题。


为什么在地球上使用lambda呢?

 okButton.Click + =(s,e )=> okButton_Click(); 

我从来没有这样做过:

 okButton.Click + =  new  EventHandler(okButton_Click); 

将完成这项工作...



但一般来说,我更喜欢将它们设置为如果我也创建了实例,我只在代码中明确地添加它们。





问题出现了,然后,当一个人需要使用lambda表达式时?如果答案很长和/或很复杂,那么可能会为我提供一些可能为其提供照明的链接。



首先,在Linq方法和表达式中,你想要做一些简短而甜蜜的事情:

  var  found = myList.Where(c = >  c.Cost <   1000 ); 



如果没有lambda这样做会使你的可读性降低很多,就像你一样d必须为这一行创建一个方法, 找到一种方法来传递循环值。



Lambdas适用于你只使用一次方法的地方,它简短易懂,它使代码更具可读性 - 当你习惯它们时,这并不困难徒步浏览半个文件以找到一行方法:

  private   bool  IsCheap(MyClass c){ return  c.Cost <  < span class =code-digit> 1000 ; } 

对可读性没有太大作用! :笑


Example will illustrate what I mean.

WinForms application with an 'OK' button and code to be executed when it's clicked.

Choice #1. Double-click the button in the IDE to create the stub within the form class.

Choice #2. Use an explicit lambda expression in the form constructor as follows:

okButton.Click += (s, e) => okButton_Click();


I was leaning towards #2 on the grounds that it shows the connection explicitly without having to look through the events in the Properties window for that control.

Not a big deal either way, but am wondering if there's a consensus about which one is preferable.

解决方案

First, I think it's great that you are diligently studying all the possible forms of creating EventHandlers, and "wiring them up" to various Control Events.

For simple uses of EventHandlers, I see lots of benefits from letting Visual Studio create stubs for the programmer via double-clicking on the Control, or selecting an Event in the Property Browser for a Control. This is a "convenience" functionality that increases your productivity, and encapsulates simple logical relations so you can focus on your "larger scale" tasks at hand.

There are no performance penalties for making use of this built-in functionality, and, if you are obsessive-compulsive, you may receive a bonus of something new to worry about, if the syntax bothers you :)

The "organic" reasons for creating your own EventHandlers in code (using Lambda expressions, anonymous methods) arise when you are doing more complex things. Obviously, if you define your own Events, you have to define your own EventHandlers to use those Events, but, let's consider some other cases in which you'd want to define your own EventHandlers:

1. When you want to directly manipulate the fact that a .NET Event is a multi-cast delegate that maintains a queue of possible EventHandlers all of which will be executed. By "manipulate" I mean remove an existing EventHandler, add an EventHandler, restore a previously removed EventHandler, etc.

2. as in #1, but with the stipulation that you want to directly manipulate the order in which EventHandlers in the Event's internal queue are executed.

3. in complex control situations where you might want to store EventHandlers. For example, imagine a Dictionary<TreeNode, CustomEvent> where you might want to execute different code based on a TreeNode. Or, imagine a "state machine" type of UI, where for each "state," you'd want to assign different EventHandlers to certain Controls that are present in the UI for each state.

An example of storing Delegates as Values in a Dictionary can be found in my article on DevX: [^]. You could store EventHandlers in exactly the same way.

Scenario #2 is one I am dealing with right now in a Project I am working on, and I have "solved" it by creating a static Property of Type Action in a static Class: under different circumstances different EventHandlers are assigned to that Property by various Forms, and the sequence of execution of the EventHandlers in response to a certain UI Event is re-structured. Sounds more exotic than it is.

This type of solution allows me to execute an EventHandler defined within various external objects (Forms) with no specific "tight coupling" between the static Class and the Forms, and, of course, since the EventHandler definition is "inside" a Form, it has access to all of the Form's private/public Fields, Methods, etc., while the static Class does not.


Actually, these aren't really two different choices. I agree with your concern, as one of the things I have always strongly disliked about certain languages and technologies (VB 6 being a great example of this, and VBA an even worse offender) is how much of this kind of hidden magic is involved in things.

But here you'll find that in neither case is there a magic, auto-subscription, though it may seem that way. When you create a form in Visual Studio, let's say "MainForm", if you look carefully, you'll note that the form class is spread out between two files, MainForm.cs and MainForm.Designer.cs, each of which starts with "partial class MainForm" meaning they both contribute code which is mashed together to compile into a single class. MainForm.cs typically contains all the stuff you add by hand (although you could create more files that contribute to the same class if you want for some reason). But the entire rest of the form-- the layout, the event subscriptions, everything-- is still done using regular old C# code, and you'll find it in MainForm.Designer.cs. The graphical editor in the IDE is just doing C# code generation, not hiding anything somewhere secret that you can't look at yourself.

So after you double-click on that button to auto-create an event handler, if you go look in the .Designer.cs file, in the method called InitializeComponent(), I think you'll see a line that looks very much like your "Choice #2," although it isn't probably using quite the same syntax (a lambda isn't actually necessary here).

I personally would think it preferable to put all this initialization in a single place most of the time, so basically I'd say just keep it consistent within an application. If you're going to use some tools other than Visual Studio for developing, and therefore create forms without using the VS graphical designer (you could do all of this in a text editor, for instance, without any graphical designer at all), or if you're going to be actively subscribing to and unsubscribing from events dynamically sometime after form initialization is complete, then you might have a good reason to put these somewhere else, but in many or most cases, I don't see why using the designer to insert these is a problem.


Why on earth use a lambda anyway?

okButton.Click += (s, e) => okButton_Click();

I've never done that, when:

okButton.Click += new EventHandler(okButton_Click);

will do the job...

But generally, I prefer to set them in the properties pane, I only explicitly add them in code if I also create the instance.


"The question arises, then, when WOULD one need to use lambda expressions? If the answer is long and/or complicated, then a link to something that might illuminate it for me would be much appreciated."

Primarily, in Linq methods and expressions, where you want to do something short and sweet:

var found = myList.Where(c => c.Cost < 1000);


To do this without a lambda would make it a lot less readable, as you'd have to create a method just for this one line, and find a way to pass the "loop" values through.

Lambdas are for places where you are only going to use the method once, it's short and easily understood, and it makes the code more readable that the equivalent - which isn't difficult when you are used to them as having to trek half a file away to find a one line method:

private bool IsCheap(MyClass c) { return c.Cost < 1000; }

Doesn't do much for readability! :laugh:


这篇关于活动订阅。最佳实践:自动(VS)还是手动(明确编码)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆