我已声明了一个通用事件处理程序
public delegate void EventHandler();
Run Code Online (Sandbox Code Playgroud)
我添加了扩展方法'RaiseEvent':
public static void RaiseEvent(this EventHandler self) {
if (self != null) self.Invoke();
}
Run Code Online (Sandbox Code Playgroud)
当我使用典型语法定义事件时
public event EventHandler TypicalEvent;
Run Code Online (Sandbox Code Playgroud)
然后我可以调用使用扩展方法没有问题:
TypicalEvent.RaiseEvent();
Run Code Online (Sandbox Code Playgroud)
但是当我使用显式添加/删除语法定义事件时
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent {
add { _explicitEvent += value; }
remove { _explicitEvent -= value; }
}
Run Code Online (Sandbox Code Playgroud)
那么使用显式添加/删除语法定义的事件上不存在扩展方法:
ExplicitEvent.RaiseEvent(); //RaiseEvent() does not exist on the event for some reason
Run Code Online (Sandbox Code Playgroud)
当我将鼠标悬停在活动上,看看它说的原因:
事件'ExplicitEvent'只能出现在+ =或 - =的左侧
为什么使用典型语法定义的事件与使用显式添加/删除语法定义的事件不同,以及为什么扩展方法不适用于后者?
编辑:我发现我可以直接使用私有事件处理程序解决它:
_explicitEvent.RaiseEvent();
Run Code Online (Sandbox Code Playgroud)
但我仍然不明白为什么我不能直接使用事件,就像使用典型语法定义的事件一样.也许有人可以开导我.
Jon*_*eet 51
当您创建"类字段"事件时,如下所示:
public event EventHandler Foo;
Run Code Online (Sandbox Code Playgroud)
编译器生成一个字段和一个事件.在声明事件的类的源代码中,只要您引用Foo编译器,就会明白您指的是该字段.但是,该字段是私有的,因此每当您Foo从其他类引用时,它都会引用该事件(因此也就是添加/删除代码).
如果您声明自己的显式添加/删除代码,则不会获得自动生成的字段.所以,你只有一个事件,你不能直接在C#中引发一个事件 - 你只能调用一个委托实例.事件不是委托实例,它只是一个添加/删除对.
现在,您的代码包含:
public EventHandler TypicalEvent;
Run Code Online (Sandbox Code Playgroud)
这仍然略有不同 - 它根本没有声明事件 - 它声明了委托类型的公共字段EventHandler.任何人都可以调用它,因为该值只是一个委托实例.了解字段和事件之间的区别非常重要.你永远不应该写这种代码,就像我确定你通常没有其他类型的公共字段,如string和int.不幸的是,这是一个简单的拼写错误,而且是一个相对难以阻止的错误.您只会通过注意编译器允许您分配或使用其他类的值来发现它.
有关更多信息,请参阅我关于事件和代理的文章.
TcK*_*cKs 37
因为你可以这样做(它是非现实世界的样本,但它"有效"):
private EventHandler _explicitEvent_A;
private EventHandler _explicitEvent_B;
private bool flag;
public event EventHandler ExplicitEvent {
add {
if ( flag = !flag ) { _explicitEvent_A += value; /* or do anything else */ }
else { _explicitEvent_B += value; /* or do anything else */ }
}
remove {
if ( flag = !flag ) { _explicitEvent_A -= value; /* or do anything else */ }
else { _explicitEvent_B -= value; /* or do anything else */ }
}
}
Run Code Online (Sandbox Code Playgroud)
编译器如何知道它应该用"ExplicitEvent.RaiseEvent();"做什么?答:不可以.
"ExplicitEvent.RaiseEvent();" 只是语法糖,只有在隐式实现事件时才可以预测.
那是因为你没有正确看待它.逻辑与Properties中的逻辑相同.一旦你设置了添加/删除它就不再是一个实际的事件,而是一个暴露实际事件的包装器(事件只能从类本身内部触发,所以你总是可以在本地访问真实事件).
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent {
add { _explicitEvent += value; }
remove { _explicitEvent -= value; }
}
private double seconds;
public double Hours
{
get { return seconds / 3600; }
set { seconds = value * 3600; }
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,具有get/set或add/remove属性的成员实际上不包含任何数据.您需要一个"真正的"私有成员来包含实际数据.这些属性只允许您在将成员公开给外部世界时编写额外的逻辑.
你想要做的一个很好的例子就是在不需要时停止额外的计算(没有人在听这个事件).
例如,假设事件是由计时器触发的,如果没有人注册事件,我们不希望计时器工作:
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent
{
add
{
if (_explicitEvent == null) timer.Start();
_explicitEvent += value;
}
remove
{
_explicitEvent -= value;
if (_explicitEvent == null) timer.Stop();
}
}
Run Code Online (Sandbox Code Playgroud)
您可能想要用对象锁定添加/删除(事后想法)......
| 归档时间: |
|
| 查看次数: |
36801 次 |
| 最近记录: |