Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在运行时使用反射检查是否订阅了给定事件_C#_Events_Reflection_Subscription - Fatal编程技术网

C# 在运行时使用反射检查是否订阅了给定事件

C# 在运行时使用反射检查是否订阅了给定事件,c#,events,reflection,subscription,C#,Events,Reflection,Subscription,考虑一个有一些事件的类。这个活动列表将会增加。有些是可选的。其他的是必需的 为了简化一些初始验证,我有一个自定义属性,将事件标记为必需事件。 例如: [RequiredEventSubscription("This event is required!")] public event EventHandler ServiceStarted; 到目前为止还不错。 为了验证所有事件,我使用反射迭代事件列表并获取自定义属性。 但我需要一种方法来确定该活动是否被订阅 在没有反射的情况下

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

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

    [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());
    }

非常感谢

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

public IEnumerable<Delegate> GetSubscribers(string eventName);

IMHO,如果订阅事件是必需的,那么首先不要将其作为事件,而是将其作为类构造函数的委托参数?谁/什么需要?@Daniel,这是我的第一个方法,但在整个代码中发送这么多的代理将引导我进行这个实验。@David,现在验证过程只需要记录一个警告。我明白你关于设计缺陷的观点:/你的解决方案仍然引导我朝着一个好的方向前进!GetField(-eventname-)和绑定标志解决了这个问题!
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();