【问题标题】:Check if a given event is subscribed, during runtime, using reflection在运行时使用反射检查给定事件是否被订阅
【发布时间】:2011-03-15 15:05:55
【问题描述】:

考虑一个有一些事件的类。这个事件列表将会增长。有些是可选的。其他是必需的。

为了简化一些初始验证,我有一个自定义属性,将事件标记为必需事件。 例如:

    [RequiredEventSubscription("This event is required!")]
    public event EventHandler ServiceStarted;

到目前为止一切顺利。 为了验证所有事件,我使用反射迭代事件列表并获取自定义属性。 但我需要一种方法来确定该事件是否被订阅。

无需反射,ServiceStarted.GetInvocationList 就可以完成这项工作。但该事件必须来自此列表: var eventList = this.GetType().GetEvents().ToList();

有没有办法检查事件列表中的给定事件是否使用反射订阅?

--[更新]-- 这是基于 Ami 的回答的可能解决方案:

    private void CheckIfRequiredEventsAreSubscribed()
    {
        var eventList = GetType().GetEvents().ToList().Where(e => Attribute.IsDefined(e, typeof(RequiredEventSubscription)));

        StringBuilder exceptionMessage = new StringBuilder();
        StringBuilder warnMessage = new StringBuilder();

        foreach (var evt in eventList)
        {
            RequiredEventSubscription reqAttr = (RequiredEventSubscription) evt.GetCustomAttributes(typeof(RequiredEventSubscription), true).First();
            var evtDelegate = this.GetType().GetField(evt.Name, BindingFlags.Instance | BindingFlags.NonPublic);
            if (evtDelegate.GetValue(this) == null)
            {
                warnMessage.AppendLine(reqAttr.warnMess);
                if (reqAttr.throwException) exceptionMessage.AppendLine(reqAttr.warnMess);
            }
        }
        if (warnMessage.Length > 0)
            Console.WriteLine(warnMessage);
        if (exceptionMessage.Length > 0)
            throw new RequiredEventSubscriptionException(exceptionMessage.ToString());
    }

非常感谢!!

【问题讨论】:

  • 恕我直言,如果需要订阅事件,首先不要将其设为事件,而是将其作为类构造函数的委托参数。
  • 什么在做验证,在这种情况下“必需”是什么意思?谁/什么需要?
  • @Daniel,这是我的第一个方法,但是在整个代码中发送了这么多的委托导致我进行了这个实验。
  • @David,现在验证过程只需要记录一个警告。

标签: c# events reflection subscription


【解决方案1】:

这里有一些主要的设计问题。一般来说,没有办法询问对象其事件的订阅者是谁。任何人都想要这个功能是非常不寻常的,但如果你真的想要它,你应该让类以某种方式公开它,例如,通过使用如下方法实现接口:

public IEnumerable<Delegate> GetSubscribers(string eventName);

无论如何,要回答所提出的问题,您可以使用反射,但前提是您确切知道订阅者的维护方式。例如, 假设 所有 事件都是使用 C# 类字段事件的当前实现来实现的,您可以执行类似的操作(强烈不鼓励):

object o = ...

var unsubscribedEvents = 
  from e in o.GetType().GetEvents()
  where Attribute.IsDefined(e, typeof(RequiredEventSubscriptionAttribute))
  let field = o.GetType()
               .GetField(e.Name, BindingFlags.NonPublic | BindingFlags.Instance)
               .GetValue(o)
  where field == null
  select field;

var isValid = !unsubscribedEvents.Any();

【讨论】:

  • 我明白你关于设计缺陷的观点:/你的解决方案仍然引导我朝着一个好的方向前进! GetField(-eventname-) 和绑定标志解决了这个问题!
猜你喜欢
  • 2011-04-05
  • 1970-01-01
  • 2015-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
  • 1970-01-01
相关资源
最近更新 更多