当EventHandler<;T>;存储在字典中
本文关键字:字典 存储 EventHandler lt gt | 更新日期: 2023-09-27 18:22:02
编辑:重写,因为我对原始问题解释得很差
问题:订阅另一个类的事件(在字典中引用)的类在事件触发时不会被调用。当所有代码都在包含事件的类中时,一切都会正常工作
我使用字典来处理基于枚举(EventType)的事件/处理程序:
Dictionary<EventType, EventHandler<EventArgs>> eventLookup;
为了填充这个字典,我通过一个包含大量事件的类进行反思,并为每个事件分配一个新的空EventHandler。然后我将EventType值与每个EventHandler关联起来:
public void EngineEvents::Initialize()
{
foreach (EventInfo eventInfo in this.GetType().GetEvents())
{
eventInfo.GetAddMethod(true).Invoke(this, new[] { new EventHandler<EventArgs>(this.UselessHandler) });
}
this.eventLookup = new Dictionary<EventType, EventHandler<EventArgs>>
{
{ EventType.Initialize, this.OnInitialize },
};
}
private void UselessHandler(object sender, EventArgs args) { }
public event EventHandler<EventArgs> OnInitialize;
其他代码可以订阅OnInitialize,并且应该接收事件。
engineEvents.OnInitialize += this.OnInitialize;
当一个事件被触发时,我索引到字典中,并调用多播委托:
public void EngineEvents::FireEvent(EventType eventType)
{
if (this.eventLookup.ContainsKey(eventType))
{
this.eventLookup[eventType](this, new EventArgs());
}
}
这对于EngineEvents(包含事件和查找字典的类)内部完成的任何操作都非常有效。
当我从以下位置订阅EngineEvents事件时:
public class CallingClass
{
public CallingClass(EngineEvents engine)
{
engine.OnInitialize += this.OnInitialize;
}
private void OnInitialize(object sender, EventArgs e)
{
Console.WriteLine("calling class's method called");
}
}
从未调用此OnInitialize,但EngineEvents中的UselessHandler为.
其他代码如何触发此事件:
engineEvents.FireEvent(EventType.Initialize);
总结如下:只有EngineEvents的EventHandlers保持相关,并且不会调用事件的外部订阅者。
控制台应用程序的完整示例。CallingClass的OnInitialize和EngineEvents的UselessHandler上的断点显示一个被调用,而不是另一个。
namespace ConsoleApplication2
{
using System;
using System.Collections.Generic;
using System.Reflection;
public class Program
{
static void Main(string[] args)
{
EngineEvents engine = new EngineEvents();
engine.Initialize();
CallingClass calling = new CallingClass(engine);
engine.FireEvent(EventType.Initialize);
}
}
public class EngineEvents
{
private Dictionary<EventType, EventHandler<EventArgs>> eventLookup;
public void Initialize()
{
foreach (EventInfo eventInfo in this.GetType().GetEvents())
{
eventInfo.GetAddMethod(true).Invoke(this, new[] { new EventHandler<EventArgs>(this.UselessHandler) });
}
this.eventLookup = new Dictionary<EventType, EventHandler<EventArgs>>
{
{ EventType.Initialize, this.OnInitialize },
};
}
private void UselessHandler(object sender, EventArgs args) { }
public event EventHandler<EventArgs> OnInitialize;
public void FireEvent(EventType eventType)
{
if (this.eventLookup.ContainsKey(eventType))
{
this.eventLookup[eventType](this, new EventArgs());
}
}
}
public enum EventType
{
Initialize,
}
public class CallingClass
{
public CallingClass(EngineEvents engine)
{
engine.OnInitialize += this.OnInitialize;
}
private void OnInitialize(object sender, EventArgs e)
{
Console.WriteLine("calling class's method called");
}
}
}
好吧,我想我明白了。
首先,您不能"将事件存储在字典中"或其他任何东西中。event
是(一种)属性,不能通过引用存储。您的字典存储这些属性的内容,委托。
发生的是:
- 您通过反射订阅UselessHandler
- 使用初始值设定项
{ EventType.Initialize, this.OnInitialize },
填充字典 - 您使用
+=
从调用类订阅另一个处理程序 - 您通过字典引发了一个"事件"
问题是,在步骤2)中,您认为正在捕获一个事件。但此时您只读取事件并存储委托值(仅包含无用处理程序)
在步骤3)中,您订阅了实际事件,字典中没有任何内容更改
在步骤4)中,只调用字典中的委托,而不调用事件中更新的委托。