C # Создать делегат, который запускает событие? - PullRequest
1 голос
/ 29 октября 2010

Можно ли использовать Reflection в C # для запуска события? Скажем, у меня такая ситуация:

public delegate void SomeEventHandler(object sender, BenArgs e);

class EventHub
{
    public event SomeEventHandler SOME_EVENT;

    public void fireEvent(String eventName)
    {
        SomeEventHandler evt = (SomeEventHandler) Delegate.CreateDelegate(typeof(SomeEventHandler), this, eventName);

        evt.Invoke(null, null);
    }
}

Значение, если я позвоню

EventHub.fireEvent("SOME_EVENT")

тогда это заставляет концентратор событий запускать SOME_EVENT? Я пробовал это и только получаю исключения.

Это в основном мое любопытство, я знаю, что в этом случае я мог бы так же легко запустить событие без отражения.

1 Ответ

3 голосов
/ 29 октября 2010

Исходя из вашего текущего сценария, т.е.

  1. Полеподобное событие.
  2. Поле делегата поддержки имеет то же имя, что и событие.
  3. (this, EventArgs.Empty) - допустимые аргументы для передачи делегату.

Вы можете сделать что-то вроде этого (требуется дополнительная проверка аргумента):

public void fireEvent(String eventName)
{
    // Get a reference to the backing field
    var del = (Delegate)typeof(EventHub)
                .GetField(eventName, BindingFlags.NonPublic | BindingFlags.Instance)
                .GetValue(this);

     // Invoke the delegate, it's invocation-list will contain the listeners
     if(del != null)
        del.DynamicInvoke(this, EventArgs.Empty);
}

Использование:

  var eHub = new EventHub();
  eHub.SOME_EVENT += delegate { Console.WriteLine("SOME_EVENT fired.."); };      
  eHub.fireEvent("SOME_EVENT");

Теперь вы можете обобщить эту идею с помощью метода расширения на object, если хотите, но все это действительно плохая идея. Эта проблема не может быть решена в общем случае, потому что никто не может знать, как событие «реализовано». Внутри методов add и remove может быть произвольный код, и логика «запуска» события также может быть чем угодно. Там может даже не быть поля резервной многоадресной рассылки для хранения слушателей.

В любом случае, попытка сказать объекту, что он запускает событие, почти всегда является признаком серьезного недостатка дизайна, ИМО. Если вы все еще действительно хотите этого, было бы намного лучше объявить такой метод в вашем классе:

public void RaiseXXXEvent() { ... } 
...