惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
博客园 - Franky
GbyAI
GbyAI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
IT之家
IT之家
酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
博客园_首页
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
Scott Helme
Scott Helme
有赞技术团队
有赞技术团队
M
MIT News - Artificial intelligence
C
CERT Recently Published Vulnerability Notes
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
L
LangChain Blog
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Hacker News: Front Page
MyScale Blog
MyScale Blog
P
Palo Alto Networks Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
AI
AI
T
Troy Hunt's Blog
Microsoft Azure Blog
Microsoft Azure Blog
阮一峰的网络日志
阮一峰的网络日志
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Vercel News
Vercel News
Microsoft Security Blog
Microsoft Security Blog
罗磊的独立博客
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
人人都是产品经理
人人都是产品经理
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
E
Exploit-DB.com RSS Feed
Attack and Defense Labs
Attack and Defense Labs

博客园 - Phoenix

Server Explorer disappeared in VS 2008 FlashGet的堕落 画一个立体的柱图 - Phoenix - 博客园 SQL2000自动备份数据库到远程机器 Vista: user does not have administrative privileges in command prompt mode. 将一个域中的MS CRM数据库部署到另外一个域中 求救手工设置笔记本IRQ的方法 用纯API写的窗体 Windows下安装SQLPlus的帮助 Oracle Listener报“TNSLSNR.exe 应用程序错误” 正则表达式超时 [导入]不使用COM组件弹出数据库连接对话框 [导入]C#: 通过动态编译获取字符串所表达的值 [导入]Asp.Net中连接Oracle [导入]全角字符的匹配 [导入]使用.Net获取OLEDB数据库的架构. [导入]使用C#在进度条中显示复制文件的进度 [导入]在SQL Server2000中修改系统表 [导入]已经毕业3个月了,怀念大学生活啊。。。
如何在外部得到一个event是否已被注册
Phoenix · 2007-12-26 · via 博客园 - Phoenix

同事有个这样的需求:需要判断一个对象的event是否已经被注册过了,如果没有,则注册一个事件来执行默认操作。
比方说类ClassA

    public class ClassA
    
{
        
public event EventHandler Event1;

        
public EventHandler Delegate1;
        
private string id;

        
protected virtual void OnEvent()
        
{
            
if (this.Event1 != null)
            
{
                
this.Event1(this, EventArgs.Empty);
            }

        }


        
public ClassA()
        
{
            
this.Delegate1 = delegate(object sender, EventArgs e)
            
{
                Console.WriteLine(
"Delegate");
            }
;
        }


        
public void Test()
        
{
            OnEvent();
        }

    }

现在在代码中已经得到一个ClassA的实例,但是如果得到其Event1的情况呢,我们首先想到了使用Reflection, 查到在Reflection中有个EventInfo类型

ClassA a = new ClassA();

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;

    
        
public void add_Event1(EventHandler value)
        
{
            
// Do addition.
        }


        
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
            
{

            }


            remove
            
{

            }

        }

真正的事件delegate是存放在一个EventHandlerList中 (请参阅MSDN: .Net Framework Developer's Guide: Handle multiple events using event properties.)
所以接下来的就是找到这个EventHandlerList和MulticastDelegate的key,然后取得这个MulticastDelegate.

使用EventHandlerList易于管理,例如在Dispose资源时,统一Fire事件时等等,但是EventHandlerList本身是线性列表的对象,当这个List里面的delegate变得非常多时,查询的效率会变得非常差. :)