问题描述
我们都熟悉 C# 事件声明的可怕之处.为了确保线程安全,标准是这样写:
We're all familiar with the horror that is C# event declaration. To ensure thread-safety, the standard is to write something like this:
public event EventHandler SomethingHappened;
protected virtual void OnSomethingHappened(EventArgs e)
{
var handler = SomethingHappened;
if (handler != null)
handler(this, e);
}
最近在这个板上的一些其他问题(我现在找不到)中,有人指出在这种情况下可以很好地使用扩展方法.这是一种方法:
Recently in some other question on this board (which I can't find now), someone pointed out that extension methods could be used nicely in this scenario. Here's one way to do it:
static public class EventExtensions
{
static public void RaiseEvent(this EventHandler @event, object sender, EventArgs e)
{
var handler = @event;
if (handler != null)
handler(sender, e);
}
static public void RaiseEvent<T>(this EventHandler<T> @event, object sender, T e)
where T : EventArgs
{
var handler = @event;
if (handler != null)
handler(sender, e);
}
}
有了这些扩展方法,你需要声明和引发一个事件是这样的:
With these extension methods in place, all you need to declare and raise an event is something like this:
public event EventHandler SomethingHappened;
void SomeMethod()
{
this.SomethingHappened.RaiseEvent(this, EventArgs.Empty);
}
我的问题:这是个好主意吗?我们是否因为没有标准的 On 方法而遗漏了什么?(我注意到的一件事是它不适用于具有显式添加/删除代码的事件.)
My question: Is this a good idea? Are we missing anything by not having the standard On method? (One thing I notice is that it doesn't work with events that have explicit add/remove code.)
推荐答案
它仍然适用于具有显式添加/删除的事件 - 您只需要使用委托变量(或者您已经存储了委托)事件名称.
It will still work with events that have an explicit add/remove - you just need to use the delegate variable (or however you've stored the delegate) instead of the event name.
但是,有一种更简单的方法可以使其成为线程安全的 - 使用无操作处理程序对其进行初始化:
However, there's an easier way to make it thread-safe - initialize it with a no-op handler:
public event EventHandler SomethingHappened = delegate {};
调用额外委托对性能的影响可以忽略不计,而且它确实使代码更容易.
The performance hit of calling an extra delegate will be negligible, and it sure makes the code easier.
顺便说一句,在您的扩展方法中,您不需要额外的局部变量 - 您可以这样做:
By the way, in your extension method you don't need an extra local variable - you could just do:
static public void RaiseEvent(this EventHandler @event, object sender, EventArgs e)
{
if (@event != null)
@event(sender, e);
}
static public void RaiseEvent<T>(this EventHandler<T> @event, object sender, T e)
where T : EventArgs
{
if (@event != null)
@event(sender, e);
}
我个人不会使用关键字作为参数名称,但它并没有真正改变调用方,所以你可以做你想做的:)
Personally I wouldn't use a keyword as a parameter name, but it doesn't really change the calling side at all, so do what you want :)
至于OnXXX"方法:您是否计划派生您的类?在我看来,大多数课程都应该是密封的.如果您这样做,您是否希望这些派生类能够引发事件?如果这两个问题的答案是否",那么不要打扰.如果两者的答案都是是",那么就这样做:)
As for the "OnXXX" method: are you planning on your classes being derived from? In my view, most classes should be sealed. If you do, do you want those derived classes to be able to raise the event? If the answer to either of these questions is "no" then don't bother. If the answer to both is "yes" then do :)
这篇关于使用扩展方法引发 C# 事件 - 这很糟糕吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!