使用lambda作为方法的Delegate.CreateDelegate会产生“方法参数长度不匹配”异常
我遇到问题,Test1会产生“System.ArgumentException:方法参数长度不匹配”,而Test2和Test3正常传递。我需要使用反射来订阅一个事件,如果我使用简单的方法,一切都可以工作,但是当我进入lambdas时,它会按预期停止工作。使用lambda作为方法的Delegate.CreateDelegate会产生“方法参数长度不匹配”异常
调试显示所有lambda表示它们是“无效<> 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;
}
编辑:
显然,这是单声道的bug。 GetInvocationList()[0]获取Delegate解决了上面例子中的问题。
但订阅事件会产生“System.InvalidCastException:无法从源类型转换为目标类型”。如果事件的类型是动作但自定义委托的不是:(如果“C”类就是这样,它抛出,如果“C”类是像上面,它通过细)
public sealed class C
{
public static event MyDel myEvent;
public delegate void MyDel(int a);
}
有没有什么不同的问题?编辑#2,事件期望MyDel
类型,但获取Action Int32。我如何将Action<T>
转换为MyDel或更好的转换为eventInfo.EventHandlerType
,因为我不知道可以有什么类型的事件。
其实在进一步调查后我发现我的target
不好。
对于在类中定义的方法,将类实例作为目标是可以的。 对于lambda表达式,我认为它是空的,至少它与null,一起工作,只要它不影响创建lambda表达式的方法内部定义的局部变量。
所以行动有一个属性目标,使用callback.Target
在Delegate.CreateDelegate
解决了这个问题。
lambda的目标实际上持有对类实例和它接触的所有本地变量(调试器显示它)的引用。
奇怪的是,它在最新的.NET上工作,也许单声道和.NET之间的细微差别。
适用于MS .NET。可能是一些单声道问题? – VinSmile
似乎错误的单声道错误。检查http://lists.ximian.com/pipermail/mono-bugs/2010-December/106824.html –
如果使用GetInvocationList()(即返回列表的第一个元素)而不是'Method',会发生什么? ?后者应该可以工作,但正如@VinSmile所说,也许是单声道问题。 –