473,399 Members | 2,159 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,399 software developers and data experts.

Events unsubscribing and resource leaks?

Hey guys

When you hook an event (c# 2.0 syntax): myEvent += MyMethodToFire;

You need to also unsubscribe it to avoid a resource leak so that the object
it is in gets garbage collected like so : myEvent -= MyMethodToFire;

That's all fine, but when you use visual studio to create events for objects
it never creates an unsubscribing reference, so is it puting in resource
leaks? Or is this being cleared somewhere that i am not seeing?

Also what is the best way to clean up a singleton class?
Sep 28 '06 #1
5 2733
Hi Daniel,
see inline.

"Daniel" <Da*****@vestryonline.comschrieb im Newsbeitrag
news:u7**************@TK2MSFTNGP06.phx.gbl...
Hey guys

When you hook an event (c# 2.0 syntax): myEvent += MyMethodToFire;

You need to also unsubscribe it to avoid a resource leak so that the
object it is in gets garbage collected like so : myEvent -=
MyMethodToFire;
Are you sure?

The event will prevent the reciever of the event (if the method is an
instance method) to be collected, not the sender. If the sende is the
reciever, this also wouldn't prevent the instance from being collected. So
where is the resource leak?
The event should only be unsubscribed, if the reciever shall ciece to
recieve the event while the sender remains to exist (and fireing the event).
>
That's all fine, but when you use visual studio to create events for
objects it never creates an unsubscribing reference, so is it puting in
resource leaks? Or is this being cleared somewhere that i am not seeing?
Since the sender will be contained by the sender, i don't think this cuold
be a problem.
>
Also what is the best way to clean up a singleton class?

Sep 28 '06 #2
Hello

I never talked of sender receiver so, i presume you are in agreement that
events do cause resource leaks if not unsubscribed from?

My issue is that my sender is a singleton class. And my receiver is an
instance created inside another singleton.

Even after unsubscribing all events in my receiver instance inside the
singleton the instance still will not be garbage collected, even with a
forced dispose.

I presume this is due to the singleton that it is in remaining? But that
does not make much sense to me as to why that would be.
"Christof Nordiek" <cn@nospam.dewrote in message
news:OO**************@TK2MSFTNGP06.phx.gbl...
Hi Daniel,
see inline.

"Daniel" <Da*****@vestryonline.comschrieb im Newsbeitrag
news:u7**************@TK2MSFTNGP06.phx.gbl...
>Hey guys

When you hook an event (c# 2.0 syntax): myEvent += MyMethodToFire;

You need to also unsubscribe it to avoid a resource leak so that the
object it is in gets garbage collected like so : myEvent -=
MyMethodToFire;

Are you sure?

The event will prevent the reciever of the event (if the method is an
instance method) to be collected, not the sender. If the sende is the
reciever, this also wouldn't prevent the instance from being collected. So
where is the resource leak?
The event should only be unsubscribed, if the reciever shall ciece to
recieve the event while the sender remains to exist (and fireing the
event).
>>
That's all fine, but when you use visual studio to create events for
objects it never creates an unsubscribing reference, so is it puting in
resource leaks? Or is this being cleared somewhere that i am not seeing?

Since the sender will be contained by the sender, i don't think this cuold
be a problem.
>>
Also what is the best way to clean up a singleton class?


Sep 28 '06 #3

Daniel wrote:
I never talked of sender receiver so, i presume you are in agreement that
events do cause resource leaks if not unsubscribed from?
In some cases, yes. In most cases, no. An event subscription is a
reference like any other reference. If the event source is garbage
collected then the reference is effectively gone and the event
subscribe may also be garbage collection (if the event subscription is
the only reference left to it).
My issue is that my sender is a singleton class. And my receiver is an
instance created inside another singleton.
This is the only exception: if the event source is static then the
event reference will live forever and the subscriber will never be
garbage collected. In your case, the event source itself isn't static,
but it's a singleton, which means that there exists a static reference
to the instance which in turn contains an event (reference) to the
receiver, so the whole thing will live for the life of your
application.
Even after unsubscribing all events in my receiver instance inside the
singleton the instance still will not be garbage collected, even with a
forced dispose.
There is no such thing as a "forced dispose". You cannot force the
garbage collector to reclaim an object. You can ask it to run, but
whether it bothers reclaiming something is up to its internal
algorithms. Garbage collection is not deterministic.

One solution to this problem is to have your event subscribers
unsubscribe when they're no longer needed, but that comes with two
problems.
1. If you know when the subscriber is "no longer needed" you have to be
sure to call its Dispose() method or it will live forever. This flies
in the face of the architectural guidelines for Dispose(), which are
that it is nice to call it, but not necessary. Suddenly it becomes
necessary in the case of your event subscribers.
2. It's not always clear when the subscriber is "no longer needed." In
some cases the only way to figure out when an object is "no longer
needed" is to know when the last (important) reference to it
disappears, which means implementing reference counting, which means
creating an ugly hybrid of C# with some C++ features. Yuck.

A better solution is to use WeakReference when subscribing to the
event. This effectively says, "I, a subscriber, am subscribing to this
event, but I do not want my subscription taken into account when
deciding whether to garbage collect me." Here is some .NET 1.1 code for
doing this, although Jon Skeet has in the past pointed out that it can
be cleaned up significantly using generics in .NET 2.0, it's all I have
for now:

#region WeakEventReference

/// <summary>
/// Used to subscribe to <em>static</emevents
/// when the subscriber wants to subscribe via a weak reference rather
than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event subscribers
to be
/// garbage collected without having to unsubscribe to the event, but
it also
/// comes with a host of concurrency considerations, not the least of
which
/// is that the event handler method on the subscriber could be called
and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public abstract class WeakEventReference : WeakReference
{
private EventInfo _provider;
private MethodInfo _subscriberMethod;

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments
that
/// <paramref name="subscriberMethod"/should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="provider"/should be expecting as a
subscriber.
/// </param>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="provider"/does not allow event handlers
/// of type <paramref name="eventHandlerType"/to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this.GetType().GetMethod("ItemAdded"),
///
typeof(EventProviderType).GetEvent("StaticEvent")) .Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider, Type eventArgumentType, Type
eventHandlerType) : base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if
(!subscriberMethod.DeclaringType.IsAssignableFrom( subscriber.GetType()))
{
throw new ArgumentException(String.Format("Cannot subscribe
an object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(),
subscriberMethod.DeclaringType), "subscriber");
}
this._subscriberMethod = subscriberMethod;
ParameterInfo[] subscriberMethodParameters =
subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method
subscribing to the event takes {0} parameters, not the required two
parameters (object, {1}).", subscriberMethodParameters.Length,
eventArgumentType), "subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type System.Object.",
subscriberMethodParameters[0]), "subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
this._provider = provider;
if (!this._provider.EventHandlerType.Equals(eventHand lerType))
{
throw new ArgumentException(String.Format("EventInfo is for
a {0} event handler, not a {1}", this._provider.EventHandlerType,
eventHandlerType), "provider");
}
}

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This
is passed explicitly
/// so to search for the <paramref name="subscriberMethod"/at the
correct
/// level of the class hierarchy, since <paramref
name="subscriber"/may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the
event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments
that
/// <paramref name="subscriberMethod"/should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="providerEvent"/should be expecting as a
subscriber.
/// </param>
/// <exception cref="MissingMethodException">
/// <paramref name="subscriberType"/does not declare a method
/// called <paramref name="subscriberMethod"/>.</exception>
/// <exception cref="MissingMemberException">
/// <paramref name="providerType"/does not declare a static event
/// called <paramref name="providerEvent"/>.</exception>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="providerEvent"/does not allow event handlers
/// of type <paramref name="eventHandlerType"/to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this, "ItemAdded",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent, Type eventArgumentType, Type eventHandlerType) :
base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberType == null)
{
throw new ArgumentNullException("subscriberType");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if (!subscriberType.IsAssignableFrom(subscriber.GetTy pe()))
{
throw new ArgumentException(String.Format("Cannot subscribe
an object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(), subscriberType),
"subscriber");
}
this._subscriberMethod =
subscriberType.GetMethod(subscriberMethod, BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
if (this._subscriberMethod == null)
{
throw new MissingMethodException(String.Format("Subscriber
of type '{0}' does not have an event handler method called '{1}'.",
subscriber.GetType(), subscriberMethod));
}
ParameterInfo[] subscriberMethodParameters =
this._subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method
subscribing to the event takes {0} parameters, not the required two
parameters (object, {1}).", subscriberMethodParameters.Length,
eventArgumentType), "subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type System.Object.",
subscriberMethodParameters[0]), "subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
if (providerType == null)
{
this._provider = null;
}
else
{
if (providerEvent == null)
{
throw new ArgumentNullException("providerEvent");
}
this._provider = providerType.GetEvent(providerEvent);
if (this._provider == null)
{
throw new
MissingMemberException(String.Format("Provider type '{0}' does not
publish a static event called '{1}'", providerType, providerEvent));
}
if
(!this._provider.EventHandlerType.Equals(eventHand lerType))
{
throw new ArgumentException(String.Format("Event
provider event is for a {0}, not a {1}",
this._provider.EventHandlerType, eventHandlerType), "providerEvent");
}
}
}

/// <summary>
/// Gets the event provider for the event to which the weak
/// reference delegate has subscribed.
/// </summary>
/// <value>Information about the event to which this weak
/// reference is subscribing.</value>
protected EventInfo Provider
{
get { return this._provider; }
}

/// <summary>
/// Gets the method information for the method to call on the
/// event subscriber.
/// </summary>
/// <value>Information about the method that this weak reference
/// is to call each time the event occurs.</value>
protected MethodInfo SubscriberMethod
{
get { return this._subscriberMethod; }
}
}

#endregion

#region SystemEventWeakReference

/// <summary>
/// Used to subscribe to static events that require <see
cref="System.EventHandler"/>,
/// when the subscriber wants to subscribe via a weak reference rather
than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event subscribers
to be
/// garbage collected without having to unsubscribe to the event, but
it also
/// comes with a host of concurrency considerations, not the least of
which
/// is that the event handler method on the subscriber could be called
and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public class SystemEventWeakReference : WeakEventReference
{
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler"),
///
typeof(EventProviderType).GetEvent("StaticEvent")) .Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider) :
base(subscriber, subscriberMethod, provider,
typeof(System.EventArgs), typeof(System.EventHandler))
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This
is passed explicitly
/// so to search for the <paramref name="subscriberMethod"/at the
correct
/// level of the class hierarchy, since <paramref
name="subscriber"/may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the
event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, this, "MyEventHandler",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent) :
base(subscriber, subscriberType, subscriberMethod,
providerType, providerEvent, typeof(System.EventArgs),
typeof(System.EventHandler))
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler")).Delega te;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers
a simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod) : this(subscriber, subscriberMethod, null)
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This
is passed explicitly
/// so to search for the <paramref name="subscriberMethod"/at the
correct
/// level of the class hierarchy, since <paramref
name="subscriber"/may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, "MyEventHandler")).Delegate;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers
a simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod) : this(subscriber,
subscriberType, subscriberMethod, null, null)
{ }

/// <summary>
/// The event handler that will really be subscribed to the event.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">Arguments giving more information about the
event.</param>
public void Handler(object sender, System.EventArgs e)
{
object sub = this.Target;
if (sub != null)
{
this.SubscriberMethod.Invoke(sub, new object[] { sender, e
});
}
else if (this.Provider != null)
{
this.Provider.RemoveEventHandler(null, this.Delegate);
}
}

/// <summary>
/// The delegate to add to the event dispatch chain.
/// </summary>
/// <value>The event handler delegate for this object's
/// <see cref="Handler"/method.</value>
public System.EventHandler Delegate
{
get { return new System.EventHandler(this.Handler); }
}
}

#endregion

Sep 28 '06 #4
Thanks Bruce very detailed.

If you call an items dispose method, you have forced a dispose?

Also if you set an item to null you tell the garbage collector to collect
this and free it.

If on doin that it still doesn't reclaim it then that is a different issue
altogether and going into that scope is a bit of overkill.

I have a singleton in my app that handles my sockets, and so when i receive
certain data over the socket i fire an event to say "Object received" and
then my subscribed receivers here that and react.

I then unsubscribe those instances that are subscribed to that, but the
singleton will remain throughout my app until the final close down where the
singleton is freed and with it the events it created.

That's all fine. It was just that i read a Microsoft article stating that if
the subscribing event is still 'alive' and an instance is subscribed to it,
then the subscribed instance will not be garbage collected, hence you must
unsubscribe then dispose the instance in order to allow garbage collection
and avoid a resource leak. As mine is a singleton this is a must i presume.

"To prevent your event handler from being invoked when the event is raised,
simply unsubscribe from the event. In order to prevent resource leaks, it is
important to unsubscribe from events before you dispose of a subscriber
object. " source: http://msdn2.microsoft.com/en-us/library/ms366768.aspx
"Bruce Wood" <br*******@canada.comwrote in message
news:11**********************@m7g2000cwm.googlegro ups.com...
>
Daniel wrote:
>I never talked of sender receiver so, i presume you are in agreement that
events do cause resource leaks if not unsubscribed from?

In some cases, yes. In most cases, no. An event subscription is a
reference like any other reference. If the event source is garbage
collected then the reference is effectively gone and the event
subscribe may also be garbage collection (if the event subscription is
the only reference left to it).
>My issue is that my sender is a singleton class. And my receiver is an
instance created inside another singleton.

This is the only exception: if the event source is static then the
event reference will live forever and the subscriber will never be
garbage collected. In your case, the event source itself isn't static,
but it's a singleton, which means that there exists a static reference
to the instance which in turn contains an event (reference) to the
receiver, so the whole thing will live for the life of your
application.
>Even after unsubscribing all events in my receiver instance inside the
singleton the instance still will not be garbage collected, even with a
forced dispose.

There is no such thing as a "forced dispose". You cannot force the
garbage collector to reclaim an object. You can ask it to run, but
whether it bothers reclaiming something is up to its internal
algorithms. Garbage collection is not deterministic.

One solution to this problem is to have your event subscribers
unsubscribe when they're no longer needed, but that comes with two
problems.
1. If you know when the subscriber is "no longer needed" you have to be
sure to call its Dispose() method or it will live forever. This flies
in the face of the architectural guidelines for Dispose(), which are
that it is nice to call it, but not necessary. Suddenly it becomes
necessary in the case of your event subscribers.
2. It's not always clear when the subscriber is "no longer needed." In
some cases the only way to figure out when an object is "no longer
needed" is to know when the last (important) reference to it
disappears, which means implementing reference counting, which means
creating an ugly hybrid of C# with some C++ features. Yuck.

A better solution is to use WeakReference when subscribing to the
event. This effectively says, "I, a subscriber, am subscribing to this
event, but I do not want my subscription taken into account when
deciding whether to garbage collect me." Here is some .NET 1.1 code for
doing this, although Jon Skeet has in the past pointed out that it can
be cleaned up significantly using generics in .NET 2.0, it's all I have
for now:

#region WeakEventReference

/// <summary>
/// Used to subscribe to <em>static</emevents
/// when the subscriber wants to subscribe via a weak reference rather
than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event subscribers
to be
/// garbage collected without having to unsubscribe to the event, but
it also
/// comes with a host of concurrency considerations, not the least of
which
/// is that the event handler method on the subscriber could be called
and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public abstract class WeakEventReference : WeakReference
{
private EventInfo _provider;
private MethodInfo _subscriberMethod;

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments
that
/// <paramref name="subscriberMethod"/should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="provider"/should be expecting as a
subscriber.
/// </param>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="provider"/does not allow event handlers
/// of type <paramref name="eventHandlerType"/to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this.GetType().GetMethod("ItemAdded"),
///
typeof(EventProviderType).GetEvent("StaticEvent")) .Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider, Type eventArgumentType, Type
eventHandlerType) : base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if
(!subscriberMethod.DeclaringType.IsAssignableFrom( subscriber.GetType()))
{
throw new ArgumentException(String.Format("Cannot subscribe
an object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(),
subscriberMethod.DeclaringType), "subscriber");
}
this._subscriberMethod = subscriberMethod;
ParameterInfo[] subscriberMethodParameters =
subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method
subscribing to the event takes {0} parameters, not the required two
parameters (object, {1}).", subscriberMethodParameters.Length,
eventArgumentType), "subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type System.Object.",
subscriberMethodParameters[0]), "subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
this._provider = provider;
if (!this._provider.EventHandlerType.Equals(eventHand lerType))
{
throw new ArgumentException(String.Format("EventInfo is for
a {0} event handler, not a {1}", this._provider.EventHandlerType,
eventHandlerType), "provider");
}
}

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This
is passed explicitly
/// so to search for the <paramref name="subscriberMethod"/at the
correct
/// level of the class hierarchy, since <paramref
name="subscriber"/may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the
event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments
that
/// <paramref name="subscriberMethod"/should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="providerEvent"/should be expecting as a
subscriber.
/// </param>
/// <exception cref="MissingMethodException">
/// <paramref name="subscriberType"/does not declare a method
/// called <paramref name="subscriberMethod"/>.</exception>
/// <exception cref="MissingMemberException">
/// <paramref name="providerType"/does not declare a static event
/// called <paramref name="providerEvent"/>.</exception>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="providerEvent"/does not allow event handlers
/// of type <paramref name="eventHandlerType"/to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this, "ItemAdded",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent, Type eventArgumentType, Type eventHandlerType) :
base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberType == null)
{
throw new ArgumentNullException("subscriberType");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if (!subscriberType.IsAssignableFrom(subscriber.GetTy pe()))
{
throw new ArgumentException(String.Format("Cannot subscribe
an object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(), subscriberType),
"subscriber");
}
this._subscriberMethod =
subscriberType.GetMethod(subscriberMethod, BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
if (this._subscriberMethod == null)
{
throw new MissingMethodException(String.Format("Subscriber
of type '{0}' does not have an event handler method called '{1}'.",
subscriber.GetType(), subscriberMethod));
}
ParameterInfo[] subscriberMethodParameters =
this._subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method
subscribing to the event takes {0} parameters, not the required two
parameters (object, {1}).", subscriberMethodParameters.Length,
eventArgumentType), "subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type System.Object.",
subscriberMethodParameters[0]), "subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method
subscribing to the event has its second parameter of type {0}, not the
required parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
if (providerType == null)
{
this._provider = null;
}
else
{
if (providerEvent == null)
{
throw new ArgumentNullException("providerEvent");
}
this._provider = providerType.GetEvent(providerEvent);
if (this._provider == null)
{
throw new
MissingMemberException(String.Format("Provider type '{0}' does not
publish a static event called '{1}'", providerType, providerEvent));
}
if
(!this._provider.EventHandlerType.Equals(eventHand lerType))
{
throw new ArgumentException(String.Format("Event
provider event is for a {0}, not a {1}",
this._provider.EventHandlerType, eventHandlerType), "providerEvent");
}
}
}

/// <summary>
/// Gets the event provider for the event to which the weak
/// reference delegate has subscribed.
/// </summary>
/// <value>Information about the event to which this weak
/// reference is subscribing.</value>
protected EventInfo Provider
{
get { return this._provider; }
}

/// <summary>
/// Gets the method information for the method to call on the
/// event subscriber.
/// </summary>
/// <value>Information about the method that this weak reference
/// is to call each time the event occurs.</value>
protected MethodInfo SubscriberMethod
{
get { return this._subscriberMethod; }
}
}

#endregion

#region SystemEventWeakReference

/// <summary>
/// Used to subscribe to static events that require <see
cref="System.EventHandler"/>,
/// when the subscriber wants to subscribe via a weak reference rather
than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event subscribers
to be
/// garbage collected without having to unsubscribe to the event, but
it also
/// comes with a host of concurrency considerations, not the least of
which
/// is that the event handler method on the subscriber could be called
and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public class SystemEventWeakReference : WeakEventReference
{
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler"),
///
typeof(EventProviderType).GetEvent("StaticEvent")) .Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider) :
base(subscriber, subscriberMethod, provider,
typeof(System.EventArgs), typeof(System.EventHandler))
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This
is passed explicitly
/// so to search for the <paramref name="subscriberMethod"/at the
correct
/// level of the class hierarchy, since <paramref
name="subscriber"/may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the
event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller's responsibility to subscribe to the event. This
event information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, this, "MyEventHandler",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent) :
base(subscriber, subscriberType, subscriberMethod,
providerType, providerEvent, typeof(System.EventArgs),
typeof(System.EventHandler))
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler")).Delega te;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers
a simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod) : this(subscriber, subscriberMethod, null)
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This
is passed explicitly
/// so to search for the <paramref name="subscriberMethod"/at the
correct
/// level of the class hierarchy, since <paramref
name="subscriber"/may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</clike this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, "MyEventHandler")).Delegate;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers
a simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod) : this(subscriber,
subscriberType, subscriberMethod, null, null)
{ }

/// <summary>
/// The event handler that will really be subscribed to the event.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">Arguments giving more information about the
event.</param>
public void Handler(object sender, System.EventArgs e)
{
object sub = this.Target;
if (sub != null)
{
this.SubscriberMethod.Invoke(sub, new object[] { sender, e
});
}
else if (this.Provider != null)
{
this.Provider.RemoveEventHandler(null, this.Delegate);
}
}

/// <summary>
/// The delegate to add to the event dispatch chain.
/// </summary>
/// <value>The event handler delegate for this object's
/// <see cref="Handler"/method.</value>
public System.EventHandler Delegate
{
get { return new System.EventHandler(this.Handler); }
}
}

#endregion

Sep 28 '06 #5
Daniel wrote:
Thanks Bruce very detailed.

If you call an items dispose method, you have forced a dispose?
No, that's not true. Calling Dispose() has nothing to do with garbage
collection. It's intended for freeing non-managed resources as soon as
possible, without having to wait for the GC to reclaim the object (when
the GC will call Dispose itself). By "non-managed" resources I mean
things like Windows file handles, references to (non-.NET) memory your
object may be holding, etc.
Also if you set an item to null you tell the garbage collector to collect
this and free it.
Also not true. There are many threads in this group talking about how
the GC works. Setting a reference variable to null has no effect on
when the GC will reclaim an object, unless the thing being set to null
is a reference from another object, but you would do that as a normal
part of your program's work anyway.
If on doin that it still doesn't reclaim it then that is a different issue
altogether and going into that scope is a bit of overkill.
I know that the weak reference delegate stuff looks like overkill, but
it's better than reference counting, which in some situations is the
only other way. If in your case you always know when your subscribing
objects are no longer needed, and you can unsubscribe from your
singleton's events at that time, then you have no need of either weak
reference delegates or reference counting. In my case I couldn't do
that.

The good news about weak reference delegates is that you write them
once, learn to use them, and then never worry about them again.
I have a singleton in my app that handles my sockets, and so when i receive
certain data over the socket i fire an event to say "Object received" and
then my subscribed receivers here that and react.

I then unsubscribe those instances that are subscribed to that, but the
singleton will remain throughout my app until the final close down where the
singleton is freed and with it the events it created.

That's all fine. It was just that i read a Microsoft article stating that if
the subscribing event is still 'alive' and an instance is subscribed to it,
then the subscribed instance will not be garbage collected, hence you must
unsubscribe then dispose the instance in order to allow garbage collection
and avoid a resource leak. As mine is a singleton this is a must i presume.
Well, you must unsubscribe. Whether you need to Dispose or not depends
entirely upon the subscribing object and whether it's holding any
non-managed resources. Probably not.

But yes, you really have only three choices:
1. Have the client object unsubscribe to the event when it determines
that it's no longer needed. This is the simplest solution but isn't
always practical because it's not always "possible" to determine that.
2. Have the client object count references to itself as a way of
determining if it's no longer needed. I explained why this is
undesirable in my previous post.
3. Use weak reference delegates, which essentially say, "This event
subscription doesn't count as a reference for purposes of garbage
collection."
"To prevent your event handler from being invoked when the event is raised,
simply unsubscribe from the event. In order to prevent resource leaks, it is
important to unsubscribe from events before you dispose of a subscriber
object. " source: http://msdn2.microsoft.com/en-us/library/ms366768.aspx
All true, IF you can determine when your subscriber object is no longer
needed in the context of your program. Sometimes that's very difficult
to do, and weak reference delegates make it unnecessary.

Sep 29 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Kirk Strauser | last post by:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I've written a fairly complex application that runs under Windows XP with ActiveState Python. I'm reasonably sure that I'm freeing all allocated...
14
by: J. Campbell | last post by:
what happens to allocated memory when a program terminates before the memory is released. For example: int main(){ int* array; int a_size = 1000; array = new int; for(int i = 0; i < a_size;...
0
by: Steve Binney | last post by:
My code makes synchronous HttpWebRequest and HttpRebResponse calls. In VS 2003, I am getting memory leaks and event handle leaks. I am closing all streams and using "using"statements. I have...
2
by: Jon Davis | last post by:
The garbage handler in the .NET framework is handy. When objects fall out of scope, they are automatically destroyed, and the programmer doesn't have to worry about deallocating the memory space...
5
by: Barry Anderberg | last post by:
I'm using a tool by Sci-Tech called the .NET Memory Profiler. We have a massive .NET/C# application here and it has been exhibiting memory leak behavior for some time. Attempting to remedy the...
15
by: Rhy Mednick | last post by:
I have a class (let's call it ClassA) that I've written which has events. In another class (let's call it ClassB) I create a collection of ClassA objects. In a third class (ClassC) I create a...
4
by: Diego Martins | last post by:
Hi all! I am doing a crude investigation of memory leaks in objects created by external libraries. Since I don't have access to the source code, I can't tell if an object are freeing its resources...
15
by: dennis.richardson | last post by:
Greetings all. Here's a problem that's been driving me nuts for the last 48 hours. I'm hoping that someone has come across this before. I have a C# Application that reads a UDP broadcast...
1
by: Florence Tissot | last post by:
We are seeing some kind of resource leak in our performance lab running an ASP.NET (2.0) application that sends and receives messages from 2 public MSMQ queues. Here's a brief summary of what are...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.