2016-12-03 7 views
2

Я хочу быть в состоянии подписаться на любое событие любого объекта, передав имя события и действие, зависящее от кода клиента. У меня следующий кодСделать DynamicMethod другим способом

public static class EventSubscriber 
{ 
    public static object Subscriber<TEventArgs>(
     this object obj, 
     string eventName, 
     Action handler, 
     Func<TEventArgs, bool> canExecute) 
    { 
     var eventInfo = obj.GetType(). 
      GetEvent(eventName); 

     if (eventInfo == null) 
      throw new ArgumentException("Event name provided does not exist", nameof(eventName)); 

     var handlerArgs = eventInfo.EventHandlerType. 
      GetMethod("Invoke"). 
      GetParameters() 
      .Select(p => p.ParameterType).ToArray(); 



     var method = new DynamicMethod("method", typeof (void), handlerArgs); 
     var generator = method.GetILGenerator(256); 
     generator.EmitCall(OpCodes.Call, handler.Method, null); 

     eventInfo. 
      AddEventHandler(
       obj, 
       method.CreateDelegate(eventInfo.EventHandlerType)); 
     return obj; 
    } 
} 

Использование кода выше:

var Polygons = new ObservableCollection<Polygon>(myList); 
Polygons.Subscriber<NotifyCollectionChangedEventArgs> 
       ("CollectionChanged", 
      () => MessageBox.Show("hello"), 
       e => e.OldItems != null); 

Это вызывает InvalidProgramException когда пожары событие. Я знаю, что это сложный вопрос, и я мог просто подписаться с помощью + =, но может ли кто-нибудь сказать, почему мой код падает? Я полагаю, что что-то не так с ILGenerator.Emit, любые предложения?

ответ

1

Вы забыли вернуться в конце DynamicMethod.

var method = new DynamicMethod("method", typeof (void), handlerArgs); 
var generator = method.GetILGenerator(256); 
generator.EmitCall(OpCodes.Call, handler.Method, null); 
generator.Emit(OpCodes.Ret); //every method must have a return statement 

А класс, компилятор создает для () => MessageBox.Show("hello") лямбды является частным. [reference]

Если вы используете метод publicstatic в классе public, он работает.

var Polygons = new ObservableCollection<Polygon>(myList); 
Polygons.Subscriber<NotifyCollectionChangedEventArgs> 
    ("CollectionChanged", 
    () => MessageBox.Show("hello"), //must in a public class and a public static method 
    e => e.OldItems != null); 
Смежные вопросы