There is no simple method to achieve this.
Preferred approach:
I don't see why you can't save the delegate. You don't have to save the instance as some field. It can be a local variable that is captured by your anonymous event handler:
EventHandler<TypeOfEventArgs> handler = null;
handler = (s, e) =>
{
// Do whatever you need to do here
// Remove event:
foo.Event -= handler;
}
foo.Event += handler;
I can't think of a single scenario where you can't use this.
Alternative approach without saving the delegate:
However, if you have such a scenario, it get's quite tricky.
You need to find the delegate that has been added as a handler to the event. Because you didn't save it, it is pretty hard to obtain it. There is no this
to get a delegate of the currently executing method.
You can't use GetInvocationList()
on the event either, because accessing an event outside the class it is defined in is restricted to adding and removing handlers, i.e. +=
and -=
.
Creating a new delegate isn't possible either. While you can get access to the MethodInfo
object defining your anonymous method, you can't get access to the instance of the class that method is declared in. This class is generated automatically by the compiler and calling this
inside the anonymous method will return the instance of the class your normal method is defined in.
The only way I found that works is to find the field - if any - that the event uses and call GetInvocationList()
on it. The following code demonstrates this with a dummy class:
void Main()
{
var foo = new Foo();
foo.Bar += (s, e) => {
Console.WriteLine("Executed");
var self = new StackFrame().GetMethod();
var eventField = foo.GetType()
.GetField("Bar", BindingFlags.NonPublic |
BindingFlags.Instance);
if(eventField == null)
return;
var eventValue = eventField.GetValue(foo) as EventHandler;
if(eventValue == null)
return;
var eventHandler = eventValue.GetInvocationList()
.OfType<EventHandler>()
.FirstOrDefault(x => x.Method == self)
as EventHandler;
if(eventHandler != null)
foo.Bar -= eventHandler;
};
foo.RaiseBar();
foo.RaiseBar();
}
public class Foo
{
public event EventHandler Bar;
public void RaiseBar()
{
var handler = Bar;
if(handler != null)
handler(this, EventArgs.Empty);
}
}
Please note that the string "Bar"
that is passed to GetField
needs to be the exact name of the field that is used by the event. This results in two problems:
- The field can be named differently, e.g. when using an explicit event implementation. You need to manually find out the field name.
- There might be no field at all. This happens if the event uses an explicit event implementation and just delegates to another event or stores the delegates in some other way.
Conclusion:
The alternative approach relies on implementation details, so don't use it if you can avoid it.