使用lambda作为方法的Delegate.CreateDelegate产生"方法参数长度不匹配"例外

时间:2017-04-18 06:20:43

标签: c# .net lambda delegates mono

我有一个问题,Test1产生" System.ArgumentException:方法参数长度不匹配"而Test2和Test3通过正常。我需要使用反射订阅一个事件,如果我使用简单的方法,一切都有效,但当我进入lambdas时,它会按预期停止工作。

调试显示所有lambda,它们是" Void<> m__0(Int32)"这是事件的正确类型,与" eventInfo.EventHandlerType"相同。

为什么会失败?或者,如何解决这个问题?

c#为在lambda中创建的方法添加更多参数,如Test1?

::完整代码:

public class A
{
    public void Test1()
    {
        var str = "aa";
        B.Subscribe(typeof(C), "myEvent", (int a) => { var any = str; }, null);
    }

    public void Test2()
    {
        B.Subscribe(typeof(C), "myEvent", (int a) => { var any = a; }, null);
    }

    public void Test3()
    {
        B.Subscribe<int>(typeof(C), "myEvent", callback, this);
    }

    public void callback(int a) { }
}

public static class B
{
    public static void Subscribe<T>(Type type, string eventName, Action<T> callback, object target)
    {
        var eventInfo = type.GetEvent(eventName, BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
        var handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, target, callback.Method);
        eventInfo.AddEventHandler(null, handler); 
    }

}

public sealed class C
{
    public static event Action<int> myEvent;
}

编辑:

显然是它的Mono bug。 GetInvocationList()[0]以获取Delegate修复上述示例中的问题。

但订阅事件会产生&#34; System.InvalidCastException:无法从源类型转换为目标类型。&#34;如果事件不是Action类型而是自定义委托类型:(如果类&#34; C&#34;就像那样,它会抛出,如果类&#34; C&#34;如上所述,它会正常传递)

public sealed class C
{
    public static event MyDel myEvent;
    public delegate void MyDel(int a);
}

这是不同的问题吗?编辑#2,事件期望MyDel类型,但获取Action Int32。如何将Action<T>转换为MyDel或更好,转换为eventInfo.EventHandlerType,因为我不知道可能会发生什么类型的事件。

1 个答案:

答案 0 :(得分:2)

实际上,经过进一步调查后,我注意到我的target不好。

对于类中定义的方法,类实例作为目标是可以的。 对于lambdas,我认为它是null,至少它与null,一起工作,只要它不会干扰在创建lambda的方法中定义的局部变量。

所以操作有一个属性目标,使用callback.Target中的Delegate.CreateDelegate解决了这个问题。

lambda的目标实际上包含对类实例及其接触的所有局部变量的引用(调试器显示它)。

奇怪的是,它适用于最新的.NET,也许是单声道和.NET之间的细微差别。