我们为什么不能通过自定义实现引发事件,而没有它们则有可能吗?看到以下代码:
public class Program
{
private EventHandler myEvent;
public event EventHandler MyEvent
{
add { myEvent += value; }
remove { myEvent -= value; }
}
public event EventHandler AnotherEvent;
public static void Main()
{
var target = new Program();
target.MyEvent(null, null); // ERROR CS0079
target.AnotherEvent(null, null); // compiles
}
}
您看到两个事件都在我的类中声明。尽管target.AnotherEvent(...)
可以正常编译,但是target.MyEvent(...)
不能:
事件MyEvent只能出现在+ =或-=的左侧。
我知道一个事件只是一个具有添加和删除方法的委托。因此AnotherEvent
由编译器翻译为加法和减法:
private EventHandler _AnotherEvent;
public event EventHandler AnotherEvent
{
add { _AnotherEvent += value; }
remove { _AnotherEvent -= value; }
}
因此,我假设对AnotherEvent
的调用已被编译器替换为对私有委托的调用,_AnotherEvent(...)
。
我说对了吗?是否有任何文档说明为什么第二个呼叫有效而前一个呼叫无效?或至少对此处的编译器有何描述?
答案 0 :(得分:3)
使用自动事件时max_execution_time
。编译器将为此创建一个字段(和一些方法),并在该字段上进行调用。因此public event EventHandler AnotherEvent;
不再存在。是语法糖。
因此无法调用非自动事件。因为在编译后的代码中找不到它。它由public event
,add_
方法代替。您只能在私有字段(生成的字段)上调用
这说明了为什么不能在类实例之外调用事件。
答案 1 :(得分:2)
它不起作用,因为现在只有一种方法可以获取实际的可调用事件处理程序。您已经注意到,只有null_resource
和add
,而不是remove
。
事件处理程序的生成代码为:
get
它添加了两个方法引用,一个用于.event [mscorlib]System.EventHandler MyEvent
{
.addon instance void ConsoleApp1.Program::add_MyEvent(class [mscorlib]System.EventHandler)
.removeon instance void ConsoleApp1.Program::remove_MyEvent(class [mscorlib]System.EventHandler)
} // end of event Program::MyEvent
,一个用于add
。如果您查看它,它将如何知道要调用的方法?如果remove
和add
比现在复杂得多怎么办?无法确定要调用哪个事件处理程序。
答案 2 :(得分:1)
它是语法糖。可以像后备字段一样调用AnotherEvent
,这是编译器提供的一种便利(AnotherEvent
是所谓的类似字段的事件)。添加自己的访问器后,事件声明将不再是类似于字段的事件,而必须通过其后备字段进行调用。
请参阅C# Language Specification的相关部分:
类似字段的事件
在包含事件声明的类或结构的程序文本中,某些事件可以像字段一样使用。成为 通过这种方式使用,事件不能是抽象的或外部的,并且必须 没有明确包含event_accessor_declarations。这样的事件可以 在允许使用字段的任何上下文中使用。该字段包含一个 委托(Delegates),它引用的事件处理程序列表 已添加到活动中。如果未添加事件处理程序, 该字段包含空值。
(重点是我的)
答案 3 :(得分:0)
建议您在添加或删除新的事件处理程序方法之前锁定事件。
说,看一下这段代码:
public event EventHandler MyEvent
{
add
{
lock (objectLock)
{
myEvent += value;
}
}
remove
{
lock (objectLock)
{
myEvent -= value;
}
}
}
public event EventHandler AnotherEvent;
起作用的原因是当代码中未提供自定义事件访问器时,编译器将自动添加它们。
请遵循此文档How to: Implement Custom Event Accessors ,以获取有关正确实现的更多详细信息以及该post的其他来源。
关于实施:
private EventHandler myEvent;
public event EventHandler MyEvent
{
add
{
lock (objectLock)
{
myEvent += value;
}
}
remove
{
lock (objectLock)
{
myEvent -= value;
}
}
}
public event EventHandler AnotherEvent;
public static void Main()
{
var target = new Program();
var myEvent = target.MyEvent;
myEvent?.Invoke(EventArgs.Empty, EventArgs.Empty);
target.AnotherEvent(null, null);
}
编辑以解释实现:
var myEvent = target.MyEvent;
对于显式事件,您必须提供自己的后备存储-委托字段或类似EventHandlerList
之类的东西,因此我们在这里只使用var
。