I am getting all events, with a certain attribute, and I want to modify these events adding a call to another method.
var type = GetType();
var events = type.GetEvents().Where(e => e.GetCustomAttributes(typeof(ExecuteAttribute), false).Length > 0);
foreach (var e in events)
{
var fi = type.GetField(e.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField);
var d = (Delegate)fi.GetValue(this);
var methods = d.GetInvocationList();
foreach (var m in methods)
{
var args = e.EventHandlerType.GetMethod("Invoke").GetParameters().Select(p => Expression.Parameter(p.ParameterType, "p")).ToArray();
var body = m.Method.GetMethodBody();
/**
TODO:
Create a new method with the body of the previous
and add a call to another method
Remove current method
Add the new created method
**/
}
}
What I want is basically what is commented above. “Modify” the subscribed methods of the event. I guess I can’t subscribe to it, because I need to pass the parameters the method is passing to the big handler (the new method).
One more example based on this question. I want to convert this:
var e += (x) =>
{
var y = x;
};
To something like this:
var e += (x) =>
{
var y = x;
BigHandler(x); // injected code
};
Or this:
var e += (x) => // new method
{
previousE(x); // previous method
BigHandler(x); // additional code
}
How can I do it?
The bigger goal:
I need to “detect” when an event is fired and call a method. I also need to send the parameters it is using.
So I can make something like:
public delegate void OnPostSaved(Post p);
[Execute]
public event OnPostSaved PostSaved;
public void Save()
{
/* save stuff */
// assume that there is already an event subscribed
PostSaved(post);
}
Then on my handler method I can check if an event from XYZ was fired, check which event was fired, retrieve the parameter and do something. For example:
public void BigHandler(string eventName, params object[] p)
{
if (eventName == "PostSaved")
{
var post = p[0] as Post;
MessageBoard.Save("User posted on the blog: " + post.Content);
}
}
I know it can be achieved using PostSharp, but I can’t use it. I need another solution.
Related
- C# Reflection, changing a method’s body
- How can I dynamically inject code into event handlers in Delphi?
Update 2010-09-27 I couldn’t find a solution neither more info on it, I still need help. Added +150 bounty.
If you’re just adding a call, it’s really easy – you don’t need to fetch all the subscribed delegates or anything like that; just subscribe with reflection:
Now, I’ve made an assumption about what you want to do – namely call your method once each time the event is raised. That’s not the same as calling your method once every time an event handler is called which is what your original code would have done. That’s much harder… but do you really need it?
(If you could give more information about the bigger goal here, it would really help.)
Note that the code I’ve provided here should work regardless of how the event is implemented – it doesn’t rely on it being a field-like event.
EDIT: Okay, here’s a complete example showing how you can add a plain
EventHandlerdelegate to any event which matches the normal eventing pattern:Note how we have to construct the exact type of delegate required – but we know we can do that from a compatible method, so long as everything follows the normal event pattern.