Проверьте, подписано ли данное событие во время выполнения, используя отражение - PullRequest
4 голосов
/ 15 марта 2011

Рассмотрим класс, в котором есть некоторые события. Этот список событий будет расти. Некоторые не являются обязательными. Другие требуются.

Чтобы упростить начальную проверку, у меня есть собственный атрибут, который помечает событие как обязательное. Например:

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

Пока все хорошо. Чтобы проверить все события, используя отражение, я перебираю список событий и собираю пользовательские атрибуты. Но мне нужен способ определить, подписано ли событие или нет.

Без отражения ServiceStarted.GetInvocationList выполняет свою работу. Но событие должно прийти из этого списка: var eventList = this.GetType (). GetEvents (). ToList ();

Есть ли способ проверить, подписано ли данное событие из списка событий с помощью отражения?

- [Update] - Вот возможное решение, основанное на ответе Ами:

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

Большое спасибо !!

1 Ответ

4 голосов
/ 15 марта 2011

Здесь есть несколько серьезных проблем с дизайном.В общем, нет возможности спросить объект, кто является подписчиками его событий.Весьма необычно, что кому-то нужна эта функциональность, но если вы действительно этого хотите, вы должны получить классы, чтобы как-то это раскрыть, например, путем реализации интерфейса с помощью метода, такого как:

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();
...