"new EventHandler(MyMethod)" allocates object on the heap?

B

Bruce Wood

In messing about with weak reference delegates, I think I've figured
something out. It seems painfully obvious now, but I just want to be
100% sure.

When I say:

collection.ItemAdded += new
ItemAddedEventHandler(this.Collection_ItemAdded);

....that "new" is creating a small object on the heap. The object
contains the necessary information for calling Collection_ItemAdded
when the event is fired. Is this so?

I believe it is, because I was placing an intermediary object between
the ItemAdded event (list of subscribers) and the delegate: an object
that held a WeakReference to the "new ItemAddedEventHandler". Every
time the event was raised, no matter how soon, I found that the
WeakReference pointed to null: the Target had already been
garbage-collected.

My conclusion is that the "new ItemAddedEventHandler" creates a
full-status object on the heap, so if I point to it via a WeakReference
(and, of course, that's the only thing pointing to it), the GC just
swoops down and collects it on the next go-around.

I'm busy revamping my WeakReference delegate structure to hold a
WeakReference to the subscribing object itself, plus MethodInfo for
calling the delegate method. That, I am sure, will have the intended
effect: provide event subscription while still allowing the subscribing
object to be garbage-collected.

Am I on the right track here? Or do I have a mistaken impression of
what's going on. For those who prefer to read code, here is my
WeakReference delegate intermediary class:

public class ItemAddingWeakReference : WeakReference
{
private EventInfo _provider;

public ItemAddingWeakReference(ItemAddingEventHandler subscriber,
EventInfo provider) : base(subscriber)
{
this._provider = provider;
}

public ItemAddingWeakReference(ItemAddingEventHandler subscriber) :
this(subscriber, null)
{ }

public void Handler(object sender, IKeyedInsertDeleteEventArgs ide)
{
ItemAddingEventHandler h = (ItemAddingEventHandler)this.Target;
if (h != null)
{
h(sender, ide);
}
else if (this._provider != null)
{
this._provider.RemoveEventHandler(null, new
ItemAddingEventHandler(this.Handler));
}
}
}

....whenever Handler is invoked, this.Target is always null (already
GC'd).
 
N

Nicholas Paldino [.NET/C# MVP]

Bruce,

You are right, delegates are reference types, and I believe you are on
the right track with your code. I would recommend creating a Generic
version of this as well (taking the delegate type and the type derived from
EventArgs).

The one thing I think is wrong is that you aren't taking the event
source in the weak reference either. This will prevent you from
unsubscribing to the event when your target has been GCed.

Hope this helps.
 
B

Bruce Wood

But I am! That's what the _provider member is all about.

Thanks for the confirmation. A generic implementation is a good idea.

This is what I get for copying sample code of the Web without really
understanding it. :) Oh well. At least now I understand!

By the way, here is the new (repaired) implementation of the above:

public class ItemAddingWeakReference : WeakReference
{
private EventInfo _provider;
private MethodInfo _subscriberMethod;

public ItemAddingWeakReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider) : base(subscriber)
{
this._provider = provider;
this._subscriberMethod = subscriberMethod;
}

public ItemAddingWeakReference(object subscriber, string
subscriberMethod, Type providerType, string providerEvent) :
this(subscriber, subscriber.GetType().GetMethod(subscriberMethod),
providerType == null || providerEvent == null ? null :
providerType.GetEvent(providerEvent))
{ }

public ItemAddingWeakReference(object subscriber, MethodInfo
subscriberMethod) : this(subscriber, subscriberMethod, null)
{ }

public ItemAddingWeakReference(object subscriber, string
subscriberMethod) : this(subscriber, subscriberMethod, null, null)
{ }

public void Handler(object sender, IKeyedInsertDeleteEventArgs
ide)
{
object sub = this.Target;
if (sub != null)
{
this._subscriberMethod.Invoke(sub, new object[] {
sender, ide });
}
else if (this._provider != null)
{
this._provider.RemoveEventHandler(null, this.Delegate);
}
}

public ItemAddingEventHandler Delegate
{
get { return new ItemAddingEventHandler(this.Handler); }
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top