我读到了如何创建事件处理程序,我发现用于创建委托和事件变量的所有教程和文章。我不明白为什么他们使用事件变量,因为我们可以像使用代码一样使用委托来创建事件处理程序:
namespace EventsTest
{
public class Counter
{
public delegate void ReachedEventHandler(object sender);
public ReachedEventHandler fireEvent;
// public event ReachedEventHandler fireevent;
private int counter = 0;
public void Add(int x, int toReach)
{
counter += x;
if (counter == toReach && fireEvent != null)
fireEvent(this);
}
}
public class Test
{
public static void Main()
{
Counter x = new Counter();
x.fireEvent += new Counter.ReachedEventHandler(CounterReachedEventHandler);
x.Add(1, 1);
}
private static void CounterReachedEventHandler(object sender)
{
Console.WriteLine("Reached!");
}
}
}
这会有效,那么制作事件变量的需求是什么?
谢谢!
答案 0 :(得分:4)
event
关键字保证封装:您无法在fireEvent
之外调用或修改Counter
。外面唯一可用的操作是订阅和取消订阅(+=
和-=
)。
关于您的代码的一些注释:
一般情况下,您应该使用EventHandler
委托,而不是在自定义ReachedEventHandler
的情况下定义您自己的等效文件(EventHandler<TEventArgs>
)和EventArgs
。
您的ReachedEventHandler
未遵循事件的标准惯例。他们应该有两个参数(object sender
和TEventArgs args
,其中TEventArgs
是EventArgs
或子类)并返回void
。
显式new Counter.ReachedEventHandler()
来电也是不必要的。
答案 1 :(得分:3)
使用event
优于delegate
的优点是编译器为您生成了添加/删除pluming。例如,如果你有:
public event EventHandler<EventArgs> FooEvent;
然后编译器会自动为您生成add
和remove
方法。这些方法将填充底层委托,并将以线程安全的方式填充,这样您就不必担心锁定底层委托。
此外,您班级的任何消费者只能向代表添加和删除处理程序,他们将无法对代表进行调用(即他们无法举起活动) 。只有你的班级才能做到这一点。
答案 2 :(得分:2)
这是阻止某人编写这样的代码:
class MyClass {
public MyClass(Counter counter) {
// Myhahaha, your base belongs to me!
counter.fireEvent = new ReachedEventHandler(reached);
}
private void reached(object sender) {
// etc...
}
}
这会消除任何其他正在侦听事件的代码,它们的事件处理程序将永远不会被调用。
事件是委托对象的访问者,它只允许+ =添加,而= =删除事件处理程序。进一步限制你永远不能删除别人的事件处理程序。与字段的访问者,属性进行比较。只允许获取和设置,它会阻止其他代码直接写入字段值。