2016-12-03 45 views
2

我希望能够通过传递事件的名称和Action依赖于客户端代码来订阅任何对象的任何事件。我有以下代码上面的代码使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") lambda创建的类是私有的。 [reference]

当您在public类中使用publicstatic方法时,它会起作用。

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