C# Reflection Programmatic Event Handlers with Cus

2019-07-03 08:03发布

问题:

Here is my problem/scenario

public class TestEventArgs : EventArgs
{
   public int ID { get; set; }
   public string Name { get; set; }
}

public event EventHandler<TestEventArgs> TestClick

How can I attach an EventHandler on TestClick by using reflection? (obj is instance, Activator.CreateInstance)

EventInfo eventClick = obj.GetType().GetEvent("TestClick");
Delegate handler = Delegate.CreateDelegate(eventClick.EventHandlerType, obj, ????);
eventClick.AddEventHandler(obj, handler);

My problem being that TestEventArgs is declared in an external dll, but ???? methodinfo above requires the signature in its delegate?

回答1:

I manage to get my code to work by following the technique describe by the following article, http://www.pelennorfields.com/matt/2009/03/13/createdelegate-error-binding-to-target-method/

In essence, if I do the following, I get the error, "Error binding to target method",

FAIL:

EventInfo eventClick = obj.GetType().GetEvent("TestClick");
Delegate handler = Delegate.CreateDelegate(
    eventClick.EventHandlerType, this, "TestClick");
eventClick.AddEventHandler(obj, handler);

SUCCESS:

But when I changed it to:

MethodInfo methodOn_TestClick = this.GetType().GetMethod("TestClick", new Type[] { typeof(object), typeof(EventArgs));

Delegate handler = Delegate.CreateDelegate(
    event_DomClick.EventHandlerType, this, methodOn_TestClick, true); // note the change here

eventClick.AddEventHandler(obj, handler);

I then used reflection in my TestClick method, to get the properties I needed out of the standard EventArgs.

eg.

public void TestClick(object sender, EventArgs e)
{
    PropertyInfo prop_ID = e.GetType().GetProperty("ID");

    int id = Convert.toInt32(prop_ID.GetValue(e, null));
}


回答2:

Do you control the source of the target assembly? If so, simply add the InternalsVisibleTo assembly attribute to the target assembly.



回答3:

If you used Activator.CreateInstance() you've got a reference to the type of your object right?

To add your own handler:

Call type.GetFields() on it, now you've got the internal fields (if the event is defined in a base class you need to first walk up the heirachy using type.BaseType to go up a level to you get to the level you need).

Once you have a FieldInfo instance for the delegate backing the event handler call GetValue() on the FieldInfo instance passing your object in. Now you've got the delegate backing the event handler. Now call FieldInfo.SetValue(myObject, Delegate.Combine(currentValue, myHandler)).

I'm pretty sure that with Delegate.Combine you just have to make sure the signature of your event handler matches, but not the actual type. So it should be enough to create your own delegate with the same signature.