【问题标题】:How to infer method signature of generic delegate type to call a list of delegates如何推断通用委托类型的方法签名以调用委托列表
【发布时间】:2019-04-06 03:14:45
【问题描述】:

我正在尝试创建一个事件处理程序,它将遍历相同类型的委托列表并在需要时调用它们。我最终想要的是一个“主”处理程序,它控制调用哪些子处理程序(这是用于实现默认事件处理的嵌套状态机,因此如果事件在嵌套级别中得到处理,请阻止它传播到更高级别)

我最简单的解决方案是只订阅“最深”的事件处理程序。但这并不是我真正想要的行为,我希望该处理程序的主体说明它是否真的“处理”了事件,如果没有,则调用下一个级别。

所以我的第二种方法是只有一个实际的事件订阅者。这依次遍历委托列表,并使用修改后的方法签名调用它们,如果它处理了事件,则返回一个布尔值。

我的 .NET 事件定义:

        public static event SensorChangeHandler SensorChangedEvent;
        public delegate void SensorChangeHandler(bool triggered);
        public static void TriggerSensorChange(bool triggered)
        {
            SensorChangedEvent?.Invoke(triggered);
        }

在我的“主处理程序”类中:

        List<Func<bool, bool>> myChildHandlers = new List<Func<bool, bool>>();
        public void AddChildHandler(Func<bool, bool> childHandler)
        {
            myChildHandlers.Add(childHandler);
        }

        public SensorChangeHandler GetMasterHandler()
        {
            return (bool sensorTriggered) =>
            {
                foreach(var handler in myChildHandlers)
                {
                    if(handler(sensorTriggered))
                    {
                        // event handled, so break out of loop
                        return;
                    }
                }
            };
        }

在我的调用类中:

            MasterHandler sensorChangedMaster = new MasterHandler();
            sensorChangedMaster.AddChildHandler((bool triggered) =>
            {
                if(triggered)
                {
                    // do some stuff
                    return true;
                }
                else
                {
                    // not handled
                    return false;
                }
            })
            // the actual .NET event subscriber
            SensorChangedEvent += sensorChangedMaster.GetMasterHandler();

如果我想做的只是响应 SensorChanged 事件,这可以正常工作。但我想让这种模式通用,即

MasterHandler sensorChanged = new MasterHandler<SensorChangeHandler>();            

public class MasterHandler<THandler> {
...
        List<Func<bool, THandlerArgs>> myChildHandlers = new List<Func<bool, THandlerArgs>>();
        public void AddChildHandler(Func<bool, THandlerArgs> childHandler)
        {
            myChildHandlers.Add(childHandler);
        }

        public THandler GetMasterHandler()
        {
            return (THandlerArgs args) =>
            {
                foreach(var handler in myChildHandlers)
                {
                    if(handler(args))
                    {
                        return;
                    }
                }
            };
        }
}

我是使用泛型和反射的新手,我不清楚如何获取委托参数并将它们传递给处理程序。任何建议将不胜感激!

【问题讨论】:

  • 您所描述的内容听起来像是责任链。 stackoverflow.com/questions/2635857/…
  • 您能解释一下为什么不使用addremove 事件访问器来实现这个模式吗? (我完全不明白你为什么要做这项工作,但如果你打算这样做,绕过我们在语言中投入的所有工具来帮助你做这件事似乎是不正当的。)
  • 我喜欢责任链,谢谢你的链接!这听起来确实像我想要完成的事情。 @EricLippert 这对我来说是一个学习练习,我想尝试实现一个非常适合 .NET 事件的状态机框架。我是 C# 新手,所以不太确定更改添加和删除访问器对我有什么帮助。我有一个单独的 AddChildHandler 方法的原因是我实际上不想订阅该事件,而是在 GetMasterHandler() 返回的委托中手动调用。我同意它很时髦,所以我愿意接受建议

标签: c#


【解决方案1】:

当您有一个发布者和多个订阅者时,允许订阅者之间通信的标准方法是在您的 SensorChangedEventArgs 类中提供一个布尔属性 Handled。这样,一个订阅者将处理该事件,将Handled 属性设置为 true,而所有其他订阅者将看到该事件已被处理并退出而不做任何其他事情。

在您的情况下,您似乎有多个发布者和一个订阅者,因此情况有所不同。老实说,你的架构让我很困惑。

【讨论】:

  • 哈哈,我也很困惑。我仍在尝试做一个发布者多订阅者架构,但是多个订阅者将通过一个实际的(就.NET事件而言)订阅者来获取事件。问题,更改事件参数如何允许其他订阅者看到更改的属性?你是说你会通过引用传递参数吗?此外,我不想更改事件委托签名以适应任何特定的“处理”模式。
  • EventArgs 是一个对象,将同一个对象传递给事件的所有订阅者。所以它成为订阅者的共享状态。
  • 有趣,我没有意识到这一点。如果我可以强制我的状态机具有相同的 Handled 属性的所有事件,那可能是一个很好的解决方案。我希望不要碰代表,这样我就可以将使用范围扩展到例如winforms 事件,而不必在它们周围放置包装器
  • 为了获得最大的兼容性,您的 SensorChangedEventArgs 应该从 EventArgs 继承。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多