Delegate.CreateDelegate 以 lambda 作为方法产生 "method argument length mismatch" 异常
Delegate.CreateDelegate with lambda as method produces "method argument length mismatch" exception
我有一个问题,Test1 生成 "System.ArgumentException : method argument length mismatch" 而 Test2 和 Test3 正常通过。我需要使用反射订阅一个事件,如果我使用简单的方法一切正常,但是当我进入 lambdas 时,它会按预期停止工作。
所有 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;
}
编辑:
显然是 Mono 错误。获取委托的 GetInvocationList()[0] 解决了上例中的问题。
但订阅事件会产生 "System.InvalidCastException : Cannot cast from source type to destination type." 如果事件不是 Action 类型而是自定义委托类型:(如果 class "C" 是这样,它会抛出,如果 class "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
很糟糕。
对于 class 中定义的方法,class 实例作为目标是可以的。
对于 lambda,我认为它是 null,至少它与 null 一起工作,只要它不干扰在创建 lambda 的方法中定义的局部变量。
所以Action有一个属性Target,在Delegate.CreateDelegate
中使用callback.Target
解决了问题。
lambda 的目标实际上持有对 class 实例及其接触的所有局部变量的引用(调试器显示它)。
奇怪的是它在最新的 .NET 上运行,mono 和 .NET 之间可能略有不同。
我有一个问题,Test1 生成 "System.ArgumentException : method argument length mismatch" 而 Test2 和 Test3 正常通过。我需要使用反射订阅一个事件,如果我使用简单的方法一切正常,但是当我进入 lambdas 时,它会按预期停止工作。
所有 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;
}
编辑:
显然是 Mono 错误。获取委托的 GetInvocationList()[0] 解决了上例中的问题。
但订阅事件会产生 "System.InvalidCastException : Cannot cast from source type to destination type." 如果事件不是 Action 类型而是自定义委托类型:(如果 class "C" 是这样,它会抛出,如果 class "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
很糟糕。
对于 class 中定义的方法,class 实例作为目标是可以的。 对于 lambda,我认为它是 null,至少它与 null 一起工作,只要它不干扰在创建 lambda 的方法中定义的局部变量。
所以Action有一个属性Target,在Delegate.CreateDelegate
中使用callback.Target
解决了问题。
lambda 的目标实际上持有对 class 实例及其接触的所有局部变量的引用(调试器显示它)。
奇怪的是它在最新的 .NET 上运行,mono 和 .NET 之间可能略有不同。