C# - 事件关键字的优势? [英] C# - Event keyword advantages?

查看:33
本文介绍了C# - 事件关键字的优势?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近才明白 C#事件"确实如此.老实说,这真的不是什么.总结一下我的发现:event 关键字只是一个仅适用于委托的修饰符.

因此,事件的所有魔法"都是委托的操作.而已.我已经通读了很多 Microsoft 文档,但没有一句话以这种方式总结得如此简洁.继续我的发现,委托、类和结构都在同一级别"上.它们是定义对象"的方法.我的意思不是类型中的对象",而是某物"的封装概念.就像在说面向对象编程时如何使用对象"这个词一样.

无论如何,对象"具有某些修饰符.例如,密封、只读、虚拟、静态等...可以在此处.在委托的情况下,它有一个叫做event的额外的.事件使得当一个委托被声明为类的一部分时,它只根据给事件的访问修饰符公开 addremove 方法.这些方法的定义与属性的getset 类似.委托的其他操作(赋值、读取访问、方法调用等)只允许在声明事件委托的类中使用.我觉得有趣的另一件事是,所有委托都有方法 Invoke、BeginInvoke 和 EndInvoke,但您无法在 Visual Studio 中导航以查看它们,我也找不到描述它们的文档...

好的.那么在了解了所有这些之后,使用 event 关键字而不是修改委托的访问方式有什么好处? 似乎在许多情况下,我最好只声明一个没有 event 关键字的委托.我最近遇到的一个情况是我想创建一个包含 2 个事件的抽象基类.从这个基类派生的任何类都应该能够像使用它们自己的事件一样使用事件,类似于暴露给派生类的类的任何其他对象(也就是非私有的,除非派生类在另一个程序集,并且对象被声明为内部).

基本上,我希望派生类将这些事件用作它们自己的事件.这样做的唯一方法是将事件的支持变量公开为受保护的,因此派生类可以引发事件.看看代码,这看起来很愚蠢,因为我基本上定义了两次委托;一次作为保护区,另一次作为公共事件.我想,

<块引用>

制作一个名为 Event 的类不是更好吗?构造函数中动作的参数?返回的操作等同于许多人作为委托的扩展方法所做的 Raise,它检查委托是否为空,然后调用委托.Event 上唯一的公共方法是 Add 和 Remove,用于附加委托和从底层委托中删除它们(+=、-=).类可以将这些事件作为属性,例如,

public 事件发生了一些事情 { get;私人订制;}

<块引用>

这样只有那个班级才能重新分配事件.或者公共只读字段也同样有效.从构造函数返回的 out 参数由类存储并在类想要引发事件时调用.我知道这是一个笨拙的解决方法,但它可以完成工作,并且不仅允许将事件作为参数传递,而且允许派生类在基类将其定义为受保护的情况下调用 Raise 方法.

TLDR:

除了修改委托的访问方式之外,使用 event 关键字还有什么好处?

解决方案

除了修改委托的访问方式之外,使用 event 关键字还有什么好处?

使用事件关键字的主要优势.您仅在原始委托上使用事件,以防止从定义它的类的范围之外调用或清除委托,因为在事件的情况下,调用该事件是该类的责任.外部实体不应该直接调用它(他们可以而且应该间接调用事件),也不应该关心"是否有任何其他事件处理程序或参与接触它们(例如,通过分配一个完全该领域的新代表).

想要允许子类触发事件的特定情况最常见的解决方法是让定义事件的类创建一个受保护的方法,该方法只触发事件.按照惯例,这些方法将与事件同名,但带有On"前缀.

是的,您可以创建自己的类型来逻辑上表示事件,是委托的包装器,并将可以对该事件执行的功能限制为应该"能够执行它们的功能(可能稍微使用与 C# event 关键字使用的规则不同.这在其他没有 event 关键字(甚至可能是委托)的语言中经常使用.C#设计人员只是意识到这是一种非常常见的模式,并认为将关键字添加到语言中以帮助最小化创建逻辑事件"所需的样板代码是值得的.

使用 event 关键字的另一个好处是,与仅使用某种类型的委托作为属性相反,您可以使您的意图更加清晰.如果我只看到一个委托属性,则其含义通常是它代表一种方法.是的,C# 中的所有委托都是多播委托,所以这不是真的,但是人们在事件之外利用该功能是不寻常的.人们认为 Action 代表一个动作,而不是一系列动作.对于 C# 文档,事件也有特殊处理.它们都是单独列出的,它们在 Visual Studio 中有不同的图标等等.这都有助于使使用该类的人一目了然地更清楚成员的意图和语义.

最后,event 关键字确保了多个线程之间的同步,这不是由 Delegate 类执行的.如果多个线程同时向一个事件添加处理程序,event 关键字确保两者都添加.如果您只是公开暴露一个委托,则有可能由于竞争条件而覆盖另一个委托,并且最终有一个处理程序掉在地板上.如果你推出自己的 Event 类,你可以提供这个功能,但它既是更多的样板代码,又是很容易搞砸的东西(要么导致竞争条件,要么过度同步导致性能下降).

I've come to recently understand that a C# 'event' really is. It isn't really anything, honestly. To sum up my findings: The event keyword is simply a modifier that only applies to delegates.

So, all the 'magic' of an event are the operations of a delegate. That's it. I've read through a lot of the Microsoft documentation, but there no sentence that summarizes in that manner so succinctly. To continue with my findings, delegate, class, and struct are all on the same 'level'. They are ways to define a 'object'. I don't mean 'object' as in the type, but an encapsulated concept of 'something'. Like how the word 'object' is used when saying object oriented programming.

Anyway, 'objects' have certain modifiers. For example, sealed, readonly, virtual, static, etc... This list can be found here. In the case of a delegate, it has the extra one called event. Event makes it so that when a delegate is declared as part of a class, it only exposes the add and remove methods as per the access modifier given to the event. These methods are defined in a similar nature to get and set of a property. Other operations of the delegate (assignment, read-access, method invocation, etc) are only allowed within the class in which the event delegate was declared. The other thing I find interesting, is that all delegates have the methods Invoke, BeginInvoke, and EndInvoke, yet you cannot navigate to view them within Visual Studio, nor could I find the documentation describing them...

Okay. So after knowing all that, what is the advantage of using the event keyword other than for modifying how the delegate can be accessed? It seems like, in many cases, I'd be better off simply declaring a delegate without the event keyword. A situation I ran into recently is that I wanted to create an abstract base class that contained 2 events. Any class that derived from this base class should be able to use the events like they are their own, similar to any other object of the class that is exposed to the derived class (aka, non-private, unless the derived class is in another assembly, and the object was declared internal).

Basically, I wanted the derived classes to use these events as their own. The only way to do this was to expose the backing variable of the events as protected, so the derived classes could raise the events. Looking at the code, this seemed pretty stupid since I was basically defining the delegate twice; once as a protected field, and the other as the public event. I thought,

Wouldn't I be better off making a class called Event that has an out parameter of an Action in the constructor? The action that is returned is equivalent to Raise that many have made as an extension method for delegates, where it checks to see if the delegate is null, and then invokes the delegate. The only public methods on Event would be Add and Remove for appending delegates and removing them from the underlying delegate (+=, -=). Classes could have these events as properties, such as,

public Event SomethingHappened { get; private set; }

so that only that class can re-assign the event. Or a public readonly field would be just as effective. The out parameter that is returned from the constructor is stored by the class and called when the class wants to raise the event. I know it is a hokey workaround, but it'll get the job done, and allows the events to not only be passed as arguments, but allow derived classes to call the Raise method if the base class defines it as protected.

TLDR:

What is the advantage of using the event keyword other than for modifying how the delegate can be accessed?

解决方案

What is the advantage of using the event keyword other than for modifying how the delegate can be accessed?

That is the primary advantage of using the event keyword. You use an event over just a raw delegate to prevent the delegate from being invoked or cleared from outside the scope of the class it is defined in, because in the case of events it is the responsibility of that class to invoke the event. External entities shouldn't be invoking it directly (they can and should be invoking the event indirectly), nor should they "care" about whether there are any other event handlers or be involved in touching them (by, for example, assigning an entirely new delegate to the field).

The specific case of wanting to allow sub-classes to fire the event is most commonly solved by having the class that defines the event creating a protected method that does nothing but fire the event. Such methods will, by convention, have the same name as the event but with "On" prefixing it.

Yes, you could create your own type that logically represents an event, is a wrapper for a delegate, and limits the functions that can be performed on that event to those that "should" be able to perform them (possibly using slightly different rules than the C# event keyword uses. This is something that is frequently used in other languages that don't have an event keyword (or possibly even delegates). The C# designers simply realized that this was a very common pattern, and felt that it was worth the energy to add the keyword to the language to help minimize the boilerplate code required to create a logical "event".

Another benefit of using the event keyword, as opposed to just having some type of delegate as a property, is that you make your intentions much clearer. If I see just a delegate property the implication is generally that it represents one method. Yes, all delegates in C# are multicast delegates, so that's not true, but it's unusual for people to leverage that functionality outside of events. People think that an Action represents one action, not a list of actions. Events also have special treatment with respect to the C# documentation. They are all listed separately, they have different icons in visual studio, etc. This all helps make the intentions and semantics of the member much clearer to someone using the class at a glance.

Finally, the event keyword ensures that there is synchronization between multiple threads, which isn't performed by the Delegate class. If multiple threads go to add handlers to an event at the same time, the event keyword ensures both are added. If you just publicly expose a delegate it's possible for one to overwrite the other due to a race condition and have one handler end up dropped on the floor. If you roll your own Event class you could provide this functionality, but it is both more boilerplate code and something that's pretty darn easy to mess up (either resulting in leaving race conditions in, or excessive synchronization resulting in lost performance).

这篇关于C# - 事件关键字的优势?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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