How to get event name in called method

2019-02-26 14:10发布

问题:

I am using reflection to add an event handler to an event :

var eventInfo = type.GetEvent(eventName);
MethodInfo mi = GetType().GetMethod("TestMethod", 
           BindingFlags.Instance | BindingFlags.NonPublic);
var delegateForMethod = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, mi);
eventInfo.AddEventHandler(this, delegateForMethod);

This successfully calls my test method when the event occurs which is great, but now I need to know the name of the event that ended up calling this method...

void TestMethod(object sender, EventArgs e)
{
    // I know the sender, but which event was fired on the sender?
}

The reason I need this is because I have this generic register method which hooks up handlers to different types, and different events and channels them all to one method, while also making a note of what was attached. Once the test method fires, I need to pull out that note and use the info to notify the correct object that their "desired" event has fired. -- but to know this I need to know the event name as well as the type.

For example, in register I added Event A in type X for object O.... now when I see it triggered in the test method, I need to know it was Event A in type X, so I can notify object O by a certain interface method on it.

回答1:

There is no problem that canot be solved by introducing an additional level of abstraction!

Bind event like this:

obj.SomeEvent += (sender, args) => TestMethod("SomeEvent", sender, args);

or by reflection:

var eventInfo = type.GetEvent(eventName);
EventHandler delegateForMethod = (o, args) => TestMethod(eventInfo.Name, o, args);
eventInfo.AddEventHandler(this, delegateForMethod);

And in handler you can access event name from parameter:

void TestMethod(string eventName, object sender, EventArgs e)
{
    // eventName is event was fired on the sender
    TestMethod(sender, e);
}


回答2:

Crazy thinking here.

To every event you are going to add TestMethod, before TestMethod you add an anonimous method, wich I will call SetEventName for understanding purposes.

That SetEventName just sets some GlobalEventName variable in your class taking eventName. (I suppose there's a way to use a lambda expression for that).

So, every time the event is fired. SetEventName is called. Your GlobalEventName is set. Then TestMethod is called. And inside TestMethod, use the GlobalEventName to do your job.


See an idea (sorry, I don't understand reflection quite well to put a ready-to-use code, but that's the idea)

var eventInfo = type.GetEvent(eventName);

Action<object, EventArgs> SetEventName = (Ob, Args) => GlobalEventName = eventName;
//I really don't know if it would work but....

Add that to the eventInfo before adding the TestMethod.

MethodInfo mi = GetType().GetMethod("TestMethod", 
       BindingFlags.Instance | BindingFlags.NonPublic);
var delegateForMethod = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, mi);
eventInfo.AddEventHandler(this, delegateForMethod);

And your testmethod:

void TestMethod(object sender, EventArgs e)
{
    //Use the GlobalEventName to get event's name.
    // I know the sender, but which event was fired on the sender?
}