使用 lambda 作为方法的 Delegate.CreateDelegate 会产生“方法参数长度不匹配”异常

Jus*_*s G 3 .net c# mono lambda delegates

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

调试显示所有 lambda 表达式都是“Void <>m__0(Int32)”,这是事件的正确类型,并且与“eventInfo.EventHandlerType”相同。

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

C# 是否会像 Test1 中那样向由 lambda 创建的方法添加更多参数?

::完整代码在这里:

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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

显然这是 Mono 的 bug。GetIncationList()[0] 获取委托修复了上例中的问题。

但订阅事件会产生“System.InvalidCastException:无法从源类型转换为目标类型”。如果事件不是 Action 类型而是自定义委托:(如果类“C”是这样的,它会抛出,如果类“C”像上面那样,它会顺利通过)

public sealed class C
{
    public static event MyDel myEvent;
    public delegate void MyDel(int a);
}
Run Code Online (Sandbox Code Playgroud)

是不同的问题吗?编辑 #2,事件需要MyDel类型,但获取 Action Int32。我如何从 转换Action<T>为 MyDel 或更好地转换为eventInfo.EventHandlerType,因为我不知道可能存在什么类型的事件。

Jus*_*s G 5

事实上,经过进一步调查,我发现我的target很糟糕。

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

所以Action有一个属性Target,使用callback.TargetinDelegate.CreateDelegate可以解决问题。

lambda 的目标实际上保存了对类实例及其涉及的所有局部变量的引用(调试器显示它)。

奇怪的是它可以在最新的 .NET 上运行,也许 mono 和 .NET 之间有细微的差别。