通过c#中的反射来提升事件 [英] Raise an event via reflection in c#
问题描述
我想要写一个可重用的功能来通过反射来引发一个事件。
I want to write a reusable function to raise an event via reflection.
搜索后,我发现这个类似的问题:如何通过反思在.NET / C#?
After searching, I found this similar question: How do I raise an event via reflection in .NET/C#?
它工作,直到我注册一个事件处理程序到WinForm控件,并尝试调用它。私人字段'< EventName>
'简单地消失。
It works until I register an event handler to WinForm control and try to invoke it. The private field '<EventName>
' simply disappears.
以下是我简化的代码,重现了这个问题:
Below is my simplified code which reproduces the problem:
Program.cs:
Program.cs:
public static void Main()
{
Control control = new Control();
control.Click += new EventHandler(control_Click);
MethodInfo eventInvoker = ReflectionHelper.GetEventInvoker(control, "Click");
eventInvoker.Invoke(control, new object[] {null, null});
}
static void control_Click(object sender, EventArgs e)
{
Console.WriteLine("Clicked !!!!!!!!!!!");
}
这是我的ReflectionHelper类:
Here is my ReflectionHelper class:
public static class ReflectionHelper
{
/// <summary>
/// Gets method that will be invoked the event is raised.
/// </summary>
/// <param name="obj">Object that contains the event.</param>
/// <param name="eventName">Event Name.</param>
/// <returns></returns>
public static MethodInfo GetEventInvoker(object obj, string eventName)
{
// --- Begin parameters checking code -----------------------------
Debug.Assert(obj != null);
Debug.Assert(!string.IsNullOrEmpty(eventName));
// --- End parameters checking code -------------------------------
// prepare current processing type
Type currentType = obj.GetType();
// try to get special event decleration
while (true)
{
FieldInfo fieldInfo = currentType.GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField);
if (fieldInfo == null)
{
if (currentType.BaseType != null)
{
// move deeper
currentType = currentType.BaseType;
continue;
}
Debug.Fail(string.Format("Not found event named {0} in object type {1}", eventName, obj));
return null;
}
// found
return ((MulticastDelegate)fieldInfo.GetValue(obj)).Method;
}
}
附加信息:
- 同一类的事件:工作。
- 事件在不同的类中,子类在同一个程序集中:工作。
- 事件在 MY 不同的程序集,调试和释放模式:工作。
- WinForm,DevExpress,...中的事件:没有工作
- Event in same class: worked.
- Event in different class, sub-class in same assembly: worked.
- Event in MY different assembly, debug & release mode: worked.
- Event in WinForm, DevExpress, ...: did not work
任何帮助赞赏。
推荐答案
WinForms中的事件通常被覆盖,而不是一个一对一的委托支持。相反,类(基本上)具有事件 - >委托映射的字典,并且仅在添加事件时才创建代理。所以你不能假设有一个代理人支持事件,一旦你访问了反射的领域。
Events in WinForms are generally overridden and not don't have a one-to-one delegate backing. Instead the class (basically) has a dictionary of the event->delegate mappings and the delegates are only created when the events are added. So you can't assume there's a delegate backing the event once you access the field with reflection.
编辑:这是同样的问题的牺牲品,但比获得它作为一个字段并投射它。
this falls prey to the same problem, but is better than getting it as a field and casting it.
var eventInfo = currentType.GetEvent(eventName);
var eventRaiseMethod = eventInfo.GetRaiseMethod()
eventRaiseMethod.Invoke()
这篇关于通过c#中的反射来提升事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!