1

I need to remove all event bindings for every object in my system. There are thousands of objects that are holding events and this is causing memory leaks. I'm under a serious time constraint to get this sorted so I'm wondering if there's a way to recursively loop through an object hierarchy to remove the event bindings?

DaveDev
  • 41,155
  • 72
  • 223
  • 385

2 Answers2

1

NOTE: This is all really hacky stuff, and I do not condone its usage!

That said...yeah, you can. Kinda.

Say you've got a class Foo:

public class Foo
{
    public event EventHandler SomeEvent;
    public void Trigger()
    {
        if(SomeEvent != null)
        {
            SomeEvent(this, new EventArgs());
        }
    }
}

We new one of these up, and connect to the event in a variety of ways:

public class Bar
{
    public Bar(Foo foo)
    {
        foo.SomeEvent += FooEvent;
    }
    public void FooEvent(object sender, EventArgs e)
    {
        Console.WriteLine("Bar.FooEvent!");
    }
}

var foo = new Foo();
var bar = new Bar(foo);
foo.SomeEvent += (o,e) => Console.WriteLine("SomeEvent");

Console.WriteLine("Normal");
foo.Trigger();

Output:

Normal
Bar.FooEvent!
SomeEvent

All normal so far, right?

Now - the nastiness that is allowable via Reflection:

First, we'll need references to the EventInfo and the remove method for the event:

var theFooEvent = foo.GetType().GetEvent("SomeEvent");
var theFooRemover = theFooEvent.GetRemoveMethod(true);

Next, we'll abuse Expressions a bit to get the "present value":

var exp = 
    System.Linq.Expressions.Expression.PropertyOrField(
        System.Linq.Expressions.Expression.Constant(foo), 
        "SomeEvent");
var member = exp.Member;
var rtMember = (member as FieldInfo).GetValue(foo) as EventHandler;

We're halfway there - now to blow away all the existing handlers:

var handlers = rtMember.GetInvocationList();
foreach(var handler in handlers)
{
    theFooRemover.Invoke(foo, new[] { handler });
}

There...that's it! Further calls to Trigger won't actually do anything:

Console.WriteLine("Post hackery");
foo.Trigger();

Output:

Post hackery
JerKimball
  • 16,584
  • 3
  • 43
  • 55
0

Nasty. It doesn't look possible with reflection unless you know the names of the event handlers; is it possible to modify the Dispose methods of your objects to remove their members' event handlers?

Steve Westbrook
  • 1,698
  • 2
  • 20
  • 21