当EventHandler <t>存储在字典中时,添加的第二个事件未被注册/调用

时间:2015-11-15 09:17:47

标签: c# events delegates

编辑:重写,因为我对原始问题的解释很差。

问题:在事件触发时,不会调用订阅字典中引用的其他类事件的类。当所有代码都在包含事件的类中时,一切正常。

我使用字典允许我根据枚举(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&#39;来自:

的活动
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&#39; EventHandler保持相关性,并且不会调用事件的外部订阅者。

完整示例,适用于控制台应用程序。 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");
        }
    }
}

1 个答案:

答案 0 :(得分:1)

好的,我想我明白了。

首先,你不能将事件存储在一个词典中。或者其他任何东西。 event是(一种)属性,不能通过引用存储。您的词典存储了这些属性的内容,代表。

会发生什么:

  1. 您通过反映订阅了UselessHandler
  2. 您使用初始化程序{ EventType.Initialize, this.OnInitialize },
  3. 填充字典
  4. 您使用+=
  5. 订阅了调用类中的另一个处理程序
  6. 你举办了一场活动&#39;通过字典。
  7. 问题在于,在步骤2)您认为您正在捕获事件。但是您只是在那一刻读取事件并存储委托值(仅包含无用处理程序)

    在步骤3)中,您订阅实际事件,字典内的任何内容都不会更改

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