简体   繁体   English

使用反射来指定委托的类型(附加到事件)?

[英]Using reflection to specify the type of a delegate (to attach to an event)?

What I effectively want to do is something like this (I realise this is not valid code):我实际上想要做的是这样的事情(我意识到这不是有效的代码):

// Attach the event.
try
{
    EventInfo e = mappings[name];
    (e.EventHandlerType) handler = (sender, raw) =>
    {
        AutoWrapEventArgs args = raw as AutoWrapEventArgs;
        func.Call(this, args.GetParameters());
    };

    e.AddEventHandler(this, handler);
}
...

Now I know that the e.EventHandlerType will always derive from EventHandler<AutoWrapEventArgs>.现在我知道 e.EventHandlerType 将始终派生自 EventHandler<AutoWrapEventArgs>。 However, I can't just do:但是,我不能这样做:

    EventHandler<AutoWrapEventArgs> handler = (sender, raw) =>
    {
        AutoWrapEventArgs args = raw as AutoWrapEventArgs;
        func.Call(this, args.GetParameters());
    };

    e.AddEventHandler(this, handler);

As .NET complains that there is no conversion applicable from EventHandler<AutoWrapEventArgs> to EventHandler<DataEventArgs> when AddEventHandler is called.由于 .NET 抱怨在调用 AddEventHandler 时没有适用于从 EventHandler<AutoWrapEventArgs> 到 EventHandler<DataEventArgs> 的转换。 This is the exact message:这是确切的消息:

Object of type 'System.EventHandler`1[IronJS.AutoWrapObject+AutoWrapEventArgs]'
cannot be converted to type
'System.EventHandler`1[Node.net.Modules.Streams.NodeStream+DataEventArgs]'.

I have also tried using Invoke to dynamically use the constructor of e.EventHandlerType, but there's no way to pass the delegate definition to Invoke()'s parameter list (because there is no conversion from delegate to object).我也尝试过使用 Invoke 来动态使用 e.EventHandlerType 的构造函数,但是无法将委托定义传递给 Invoke() 的参数列表(因为没有从委托到对象的转换)。

Is there a way I can use reflection to get around this problem?有没有办法可以使用反射来解决这个问题?

Bingo: The trick is to get a reference to the constructor for the delegate type and then invoke it using the following parameters: Bingo:诀窍是获取对委托类型的构造函数的引用,然后使用以下参数调用它:

  • The target object of the delegate (backend.Target)委托的目标 object (backend.Target)
  • The delegate's pointer (backend.Method.MethodHandle.GetFunctionPointer())委托的指针 (backend.Method.MethodHandle.GetFunctionPointer())

The actual code that does this looks like (t in this case is the generic argument provided to EventHandler<> during inheritance):执行此操作的实际代码如下所示(在这种情况下,t 是在继承期间提供给 EventHandler<> 的通用参数):

Type t = e.EventHandler.GetGenericArguments()[0];
Delegate handler = (Delegate)
    typeof(EventHandler<>)
    .MakeGenericType(t)
    .GetConstructors()[0]
    .Invoke(new object[]
        {
            backend.Target,
            backend.Method.MethodHandle.GetFunctionPointer()
        });

You can then use the delegate for the event adding like so:然后,您可以使用委托来添加事件,如下所示:

e.AddEventHandler(this, handler);

You can use Delegate.CreateDelegate to accomplish your goal like this:您可以使用Delegate.CreateDelegate来完成您的目标,如下所示:

public void RegisterHandler(string name)
{
    EventInfo e = mappings[name];
    EventHandler<AutoWrapEventArgs> handler = (s, raw) =>
        {
            func.Call(this, raw.GetParameters());
        };
    e.AddEventHandler(this, Delegate.CreateDelegate(e.EventHandlerType, null, handler.Method));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM