使用委托/事件在c#中的一个地方处理所有子事件?

时间:2019-04-02 13:31:02

标签: c# .net events delegates

让我们假设我们有MissionA,MissionB,并且我们希望在任何任务开始时进行广播。如何在C#中实现?

类似于以下内容(它们分别位于不同的.cs文件中):

总干事(在MissionGeneral.cs中):

namespace MissionGeneral
{
    public class MissionGeneral
    {
        public delegate void MissionStartedEvent(string name);
        public event MissionStartedEvent OnMissionStart;
    }
}

子任务A(在MissionA.cs中):

namespace MissionA
{
    public class MissionA
    {
        public delegate void MissionStartedEvent(string name);
        public event MissionStartedEvent OnMissionStart;
        protected virtual void HandleMissionStartedEvent()
        {
            OnMissionStart?.Invoke("MissionA");
        }
    }
}

子任务B(在MissionB.cs中):

namespace MissionB
{
    public class MissionB
    {
        public delegate void MissionStartedEvent(string name);
        public event MissionStartedEvent OnMissionStart;
        protected virtual void HandleMissionStartedEvent()
        {
            OnMissionStart?.Invoke("MissionB");
        }
    }
}

Broadcaster(在Broadcaster.cs中):

using MissionGeneral;    

namespace Broadcaster
{
    public class Broadcaster
    {
        public MissionGeneral mission = new MissionGeneral();

        public Broadcaster()
        {
            mission.OnMissionStart += (_name) =>
            {
                Console.WriteLine($"This is {_name}");
                if (_name == "MissionA") Console.WriteLine("Additional MissionA info");
                else if (_name == "MissionB") Console.WriteLine("Additional MissionB info");
            };
        }
    }
}

1 个答案:

答案 0 :(得分:0)

执行此操作的方法是:

  1. 将触发事件的对象传递给事件

    public delegate void MissionStartedEvent(MissionGeneral sender);
    public event MissionStartedEvent OnMissionStart;
    
  2. 让对象本身向处理程序提供所需的信息:

    public Broadcaster()
    {
        mission.OnMissionStart += (sender) =>
        {
            Console.WriteLine($"This is {sender.Name}");
            Console.WriteLine($"Additional info: {sender.AdditionalInfo}");
        };
    }
    

如果MissionGeneral的每个子类型必须具有NameAdditionalInfo或其他的特定实现,则在基类中创建这些方法virtual并在必要时覆盖它们

如果需要在事件处理程序中访问特定于子类型的成员,则可以始终进行模式匹配(这不是很好的方案,但是比基于字符串识别类型要好得多):

 mission.OnMissionStart += (sender) =>
 {
     Console.WriteLine($"This is {sender.Name}");

     switch (sender) {
         case MissionA a:
             Console.WriteLine(a.SomeSpecificMissionAMember);
             break;
         case MissionB b:
             Console.WriteLine(b.SomeSpecificMissionAMember);
             break; }
 }