当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");
        }
    }
}

当EventHandler<;T>;存储在字典中

好吧,我想我明白了。

首先,您不能"将事件存储在字典中"或其他任何东西中。event是(一种)属性,不能通过引用存储。您的字典存储这些属性的内容,委托。

发生的是:

  1. 您通过反射订阅UselessHandler
  2. 使用初始值设定项{ EventType.Initialize, this.OnInitialize },填充字典
  3. 您使用+=从调用类订阅另一个处理程序
  4. 您通过字典引发了一个"事件"

问题是,在步骤2)中,您认为正在捕获一个事件。但此时您只读取事件并存储委托值(仅包含无用处理程序)

在步骤3)中,您订阅了实际事件,字典中没有任何内容更改

在步骤4)中,只调用字典中的委托,而不调用事件中更新的委托。