【问题标题】:Make DynamicMethod call other method让 DynamicMethod 调用其他方法
【发布时间】:2016-12-03 23:02:56
【问题描述】:

我希望能够通过传递事件的名称和依赖于客户端代码的操作来订阅任何对象的任何事件。我有以下代码

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 有问题,有什么建议吗?

【问题讨论】:

    标签: c# reflection cil dynamicmethod ilgenerator


    【解决方案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
    

    编译器为() =&gt; MessageBox.Show("hello") lambda 创建的类是私有的。[reference]

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多