同事有个这样的需求:需要判断一个对象的event是否已经被注册过了,如果没有,则注册一个事件来执行默认操作。
比方说类ClassA
public class ClassA
{
public event EventHandler Event1;
![](/Images/OutliningIndicators/InBlock.gif)
public EventHandler Delegate1;
private string id;
![](/Images/OutliningIndicators/InBlock.gif)
protected virtual void OnEvent()
{
if (this.Event1 != null)
{
this.Event1(this, EventArgs.Empty);
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public ClassA()
{
this.Delegate1 = delegate(object sender, EventArgs e)
{
Console.WriteLine("Delegate");
};
}
![](/Images/OutliningIndicators/InBlock.gif)
public void Test()
{
OnEvent();
}
}
现在在代码中已经得到一个ClassA的实例,但是如果得到其Event1的情况呢,我们首先想到了使用Reflection, 查到在Reflection中有个EventInfo类型
ClassA a = new ClassA();
![](/Images/OutliningIndicators/None.gif)
EventInfo ei = typeof(ClassA).GetEvent("Event1");
可是这个EventInfo只能通过
void AddEventHandler(object target, Delegate handler);
void RemoveEventHandler(object target, Delegate handler);
这两个方法对已知的target进行事件的Hook up (http://msdn2.microsoft.com/zh-cn/library/ms228976.aspx),无法使用如PropertyInfo, FieldInfo之类的GetValue方法得到一个MulticastDelegate实例。
后来想想,事件的声明和公有Field的声明一样,唯独多了一个event关键字,但是采用这种方式还是不能得到一个FieldInfo
FieldInfo fi = typeof(ClassA).GetField("Event1", BindingFlags.Public | BindingFlags.Instance);
不甘心之余用ildasm查看了一下,终于发现一个简单的event声明,编译器实际上处理了如下操作:
private event EventHandler Event1;
![](/Images/OutliningIndicators/None.gif)
public void add_Event1(EventHandler value)
{
// Do addition.
}
![](/Images/OutliningIndicators/None.gif)
public void remove_Event1(EventHandler value)
{
// Do removal.
}
所以实际上我们必须是得到一个私有的Field Event1,于是将代码改了改
FieldInfo fi = typeof(ClassA).GetField("Event1", BindingFlags.NonPublic | BindingFlags.Instance);
呵呵,终于能够得到一个FieldInfo的实例了,接下来使用FieldInfo.GetValue方法得到一个MulticastDelegate (未注册事件时为null). 这样我们可以对这个MulticastDelegate对象进行操作,实现真正的事件Hook up.
奇怪的是类似的代码在同事那边执行不过,用反编译工具查看了一下,发现其事件是采用自定义的方式
public event EventHandler Event2
{
add
{
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
remove
{
![](/Images/OutliningIndicators/InBlock.gif)
}
}
真正的事件delegate是存放在一个EventHandlerList中 (请参阅MSDN: .Net Framework Developer's Guide: Handle multiple events using event properties.)
所以接下来的就是找到这个EventHandlerList和MulticastDelegate的key,然后取得这个MulticastDelegate.
使用EventHandlerList易于管理,例如在Dispose资源时,统一Fire事件时等等,但是EventHandlerList本身是线性列表的对象,当这个List里面的delegate变得非常多时,查询的效率会变得非常差. :)
比方说类ClassA
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
现在在代码中已经得到一个ClassA的实例,但是如果得到其Event1的情况呢,我们首先想到了使用Reflection, 查到在Reflection中有个EventInfo类型
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
可是这个EventInfo只能通过
void AddEventHandler(object target, Delegate handler);
void RemoveEventHandler(object target, Delegate handler);
这两个方法对已知的target进行事件的Hook up (http://msdn2.microsoft.com/zh-cn/library/ms228976.aspx),无法使用如PropertyInfo, FieldInfo之类的GetValue方法得到一个MulticastDelegate实例。
后来想想,事件的声明和公有Field的声明一样,唯独多了一个event关键字,但是采用这种方式还是不能得到一个FieldInfo
![](/Images/OutliningIndicators/None.gif)
不甘心之余用ildasm查看了一下,终于发现一个简单的event声明,编译器实际上处理了如下操作:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
所以实际上我们必须是得到一个私有的Field Event1,于是将代码改了改
![](/Images/OutliningIndicators/None.gif)
奇怪的是类似的代码在同事那边执行不过,用反编译工具查看了一下,发现其事件是采用自定义的方式
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
真正的事件delegate是存放在一个EventHandlerList中 (请参阅MSDN: .Net Framework Developer's Guide: Handle multiple events using event properties.)
所以接下来的就是找到这个EventHandlerList和MulticastDelegate的key,然后取得这个MulticastDelegate.
使用EventHandlerList易于管理,例如在Dispose资源时,统一Fire事件时等等,但是EventHandlerList本身是线性列表的对象,当这个List里面的delegate变得非常多时,查询的效率会变得非常差. :)