471,319 Members | 1,580 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

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

events and object lifetime

The way I understand it, if I have an object Listener that has
registered as a listener for some event Event that's produced by an
object Emitter, as long as Emitter is still allocated Listener will
stay alive. Is this correct?
If this is correct, I've got a problem. Let's say I've got an object
Customer that has an PurchaseList (Collection) of Purchase objects.
Now, these Purchase objects were pulled from a datasource Datasource.
The datasource has a event ItemDeleted that is triggered whenever a
Purchase object is deleted. Customer has registered to listen for that
event, in order to remove the Purchase object from it's ArrayList if
nessesary. The lifetime of the Datasource is the lifetime of the app.
This means that every Customer exists in memory until the application
ends.
Is there a better way? I've thought about removing the ArrayList and
just retrieving and returning the Purchases whenever they are needed,
but that breaks a few other things I'm trying to do. Mainly, I've got
a control that encapulates the view of a Customer, that has a listview
of Purchases. When a Purchase is deleted/updated/added I'd like the
the listview to be notified (the PurchaseList fires events whenever
Purchases are added/removed/or modified). If I created the
PurchaseList each time it's was used, I'd lose that ability, each
PurchaseList would be disconnected from the datasource and be unaware
of any modifications.
Any suggestions?

Feb 14 '06 #1
16 2625
You need what's called a "weak reference delegate". That is, you want
your Datasource to hold a _weak reference_ to your Customer, not a
regular reference. Weak references don't count when the garbage
collector is deciding whether an object is still referenced and
therefore shouldn't be collected.

Here is my code for a wrapper that allows callers to "weak subscribe"
to a static event. Sorry about the length: the code includes lots of
comments. :)
#region WeakEventReference

/// <summary>
/// Used to subscribe to <em>static</em> events
/// 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</c> like 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</c> like 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</c> like 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</c> like 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</c> like 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</c> like 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

Feb 14 '06 #2
Oh, yes: and if you can stand a bit more code, here's an example of how
you use this thing:

GlobalImageCache.CurrentMeasurementSystemChanged += new
SystemEventWeakReference(this, typeof(ImagePanel),
"Instance_CurrentMeasurementSystemChanged", typeof(GlobalImageCache),
"CurrentMeasurementSystemChanged").Delegate;

Feb 14 '06 #3
an*************@gmail.com <an*************@gmail.com> wrote:
The way I understand it, if I have an object Listener that has
registered as a listener for some event Event that's produced by an
object Emitter, as long as Emitter is still allocated Listener will
stay alive. Is this correct?
Yes.
If this is correct, I've got a problem. Let's say I've got an object
Customer that has an PurchaseList (Collection) of Purchase objects.
Now, these Purchase objects were pulled from a datasource Datasource.
The datasource has a event ItemDeleted that is triggered whenever a
Purchase object is deleted. Customer has registered to listen for that
event, in order to remove the Purchase object from it's ArrayList if
nessesary. The lifetime of the Datasource is the lifetime of the app.
This means that every Customer exists in memory until the application
ends.
Is there a better way? I've thought about removing the ArrayList and
just retrieving and returning the Purchases whenever they are needed,
but that breaks a few other things I'm trying to do. Mainly, I've got
a control that encapulates the view of a Customer, that has a listview
of Purchases. When a Purchase is deleted/updated/added I'd like the
the listview to be notified (the PurchaseList fires events whenever
Purchases are added/removed/or modified). If I created the
PurchaseList each time it's was used, I'd lose that ability, each
PurchaseList would be disconnected from the datasource and be unaware
of any modifications.
Any suggestions?


Well, the view could tell the Customer to unsubscribe from the events
when the view is Disposed - assuming that only the one control uses
each Customer.

Alternatively, you *could* use a WeakReference to encapsulate the event
handler. The details are slightly complicated, but if you do a Google
search for EventHandler WeakReference you shoould find plenty of
articles about it.

There may well be other ways of reorganising your dependencies - I'll
have a think about it. No doubt others will come up with better
plans...

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Feb 14 '06 #4
Bruce Wood <br*******@canada.com> wrote:
You need what's called a "weak reference delegate". That is, you want
your Datasource to hold a _weak reference_ to your Customer, not a
regular reference. Weak references don't count when the garbage
collector is deciding whether an object is still referenced and
therefore shouldn't be collected.

Here is my code for a wrapper that allows callers to "weak subscribe"
to a static event. Sorry about the length: the code includes lots of
comments. :)


Without having studied it closely, I'm *guessing* that generics should
improve things a lot, allowing a lot of the reflection to go away. Is
that right, or am I missing something?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Feb 14 '06 #5
Thanks, I think this is the way to go. Now the question is what's up
with Visual Studio mangling pasted code? It's wrapping everything to
80 cols and breaking the comments up. Really pissing me off.

Feb 14 '06 #6
Even worse is Visual Studio crashing whenever I change the WordWrap
setting!

Feb 14 '06 #7
Yes, you're right. Generics would be a dramatic improvement. I'm still
toiling away on .NET 1.1, though. :(

Feb 14 '06 #8
That's probably the newsgroup posting itself, not Visual Studio. I have
to undo the mess when I paste into VS from newsgroup postings, too.

Feb 14 '06 #9
By the way, the "roll your own" code I posted was a response to
Googling "weak reference event handler" and finding several
(conflicting) examples of how to do it, none of which actually worked.
The code I posted, ugly as it is, and sadly pre-generics, _does_ work.
It not only provides for weak reference, but cleans up the event chain
as it discovers disposed client objects, if you choose to supply it
with a client when you subscribe.

The only thing I don't know is whether it deals "nicely" with
multithreading, so... caveat multeos threadus.

Feb 14 '06 #10
I think it's visual studio. I copied and pasted the code into a text
editor (column problems there), cleaned it up, and then pasted it into
visual studio.
Problem still occurs. Annoying.

Feb 14 '06 #11
You don't say anything about the intended lifetime of the customer objects.

Event handlers can be removed as well as added. So you may want to make your
customers implement IDisposable and have Dispose remove the handler.

<an*************@gmail.com> wrote in message
news:11**********************@z14g2000cwz.googlegr oups.com...
The way I understand it, if I have an object Listener that has
registered as a listener for some event Event that's produced by an
object Emitter, as long as Emitter is still allocated Listener will
stay alive. Is this correct?
If this is correct, I've got a problem. Let's say I've got an object
Customer that has an PurchaseList (Collection) of Purchase objects.
Now, these Purchase objects were pulled from a datasource Datasource.
The datasource has a event ItemDeleted that is triggered whenever a
Purchase object is deleted. Customer has registered to listen for that
event, in order to remove the Purchase object from it's ArrayList if
nessesary. The lifetime of the Datasource is the lifetime of the app.
This means that every Customer exists in memory until the application
ends.
Is there a better way? I've thought about removing the ArrayList and
just retrieving and returning the Purchases whenever they are needed,
but that breaks a few other things I'm trying to do. Mainly, I've got
a control that encapulates the view of a Customer, that has a listview
of Purchases. When a Purchase is deleted/updated/added I'd like the
the listview to be notified (the PurchaseList fires events whenever
Purchases are added/removed/or modified). If I created the
PurchaseList each time it's was used, I'd lose that ability, each
PurchaseList would be disconnected from the datasource and be unaware
of any modifications.
Any suggestions?

Feb 15 '06 #12
The only problem with using IDisposable in this case is that it
violates a design rule for .NET, which is that it's never _necessary_
to call Dispose() in order to free an object. Dispose() may cause the
object's resources to be freed sooner, which may be preferable to
waiting for the garbage collector to get around to cleaning them up,
but failing to call it doesn't result in a memory leak.

I had considered using IDisposable... it would certainly be simpler...
but then that would put me back in the world of C / C++ in which I'm
managing the memory. One missed call to Dispose() and I have a true
memory leak on my hands.

The WeakReference solution avoids this problem.

Feb 15 '06 #13

"Bruce Wood" <br*******@canada.com> wrote in message
news:11*********************@f14g2000cwb.googlegro ups.com...
The only problem with using IDisposable in this case is that it
violates a design rule for .NET, which is that it's never _necessary_
to call Dispose() in order to free an object.
I only say IDisposable because it has extra language support.
You could use any method.

You are not violating a design rule about resources anymore than if you held
onto the objects with a direct reference and had a method to set the
reference to null.
Dispose() may cause the
object's resources to be freed sooner, which may be preferable to
waiting for the garbage collector to get around to cleaning them up,
but failing to call it doesn't result in a memory leak.

I had considered using IDisposable... it would certainly be simpler...
but then that would put me back in the world of C / C++ in which I'm
managing the memory. One missed call to Dispose() and I have a true
memory leak on my hands.
No - true memory leaks are impossible in .NET - the objects are accessible
through the ItemDeleted event and hence are not leaks.
The WeakReference solution avoids this problem.


Weak references are a time/space trade off, no more and no less.
Feb 15 '06 #14
Nick Hounsome wrote:
The only problem with using IDisposable in this case is that it
violates a design rule for .NET, which is that it's never _necessary_
to call Dispose() in order to free an object.
I only say IDisposable because it has extra language support.
You could use any method.


.... and you would be faced with the same problem.
You are not violating a design rule about resources anymore than if you held
onto the objects with a direct reference and had a method to set the
reference to null.
Not true except for static references. If you held a direct reference
to the objects, then they would be collected when that reference were
to go out of scope. Static references, of course, never go out of
scope.

The point is still that you would have make a conscious effort to _do_
something in order that the object(s) be collected. The design ideal in
..NET is that simply having things go out of scope causes them to be
collected. Whether you use Dispose() or some other method name, you're
still left in the position of having to take some explicit action to
free the objects for collection which, if you fail to take it, leaves
them allocated for the lifetime of the running application, which is
probably not what you intended.
No - true memory leaks are impossible in .NET - the objects are accessible
through the ItemDeleted event and hence are not leaks.
Sorry. I fail to see the difference between an object that is left
hanging around until your application terminates and a "true" memory
leak. If I have a 24 x 7 application, and it continues to eat more and
more memory until it finally exhausts my system's VM and crashes, and
someone were to cheerfully point out, "But it's not a _true_ memory
leak!" I would thump them. :) Stuff that (inexplicably) doesn't get
garbage collected is a memory leak, regardless of the mechanism at work
and the level of abstraction.

What I mean by "level of abstraction" is that at a very low level of
abstraction you are correct: the objects are still accessible using
some little-known features of .NET. However, from the level of
abstraction of my program, the objects have gone out of scope but will
never be GC'd. From that point of view, it's a leak.
Weak references are a time/space trade off, no more and no less.


Not true. Weak references allow you to leave object disposal to the
garbage collector and concentrate on programming your application.
Using IDisposable, or some other disposal mechanism, requires that you
do proper memory housekeeping in order to avoid leaks (or, if you
prefer, "stuff not being garbage collected," which I maintain is
essentially the same thing). Weak references allow you to think about
static event subscribers in the same way you think about other objects
in your program: when they go out of scope, they "go away" (sooner or
later) and the memory they occupy is freed for reuse. Requiring
explicit disposal requires that you think about static event
subscribers differently: "This subscribes to a static event so I have
to explicitly dispose of it or it won't be GC'd."

Weak reference delegates allow you to decide whether subscribing to a
certain event "counts" for purposes of garbage collection. My Weak
Reference event handler wrappers allow you to express something that
native C# doesn't allow you to express (but I wish that it did): "I
want to subscribe to this event, but this subscription isn't so
important that it should keep me alive." You make your wishes known in
that regard at the moment of event subscription, and then never worry
about it again.

If you go the Dispose() route, then you have to make your wishes known
at the moment the subscribing object is no longer needed, which may not
be all that easy to determine. It leads you into strategies like
reference counting, which leads back to... C++ and manual memory
management, which flies in the face of C#'s set-it-and-forget-it,
garbage-collected mindset.

That, to me, far outweighs the time / space aspects.

Feb 15 '06 #15

"Bruce Wood" <br*******@canada.com> wrote in message
news:11**********************@g14g2000cwa.googlegr oups.com...
Nick Hounsome wrote:
> The only problem with using IDisposable in this case is that it
> violates a design rule for .NET, which is that it's never _necessary_
> to call Dispose() in order to free an object.
I only say IDisposable because it has extra language support.
You could use any method.


... and you would be faced with the same problem.


yes
You are not violating a design rule about resources anymore than if you
held
onto the objects with a direct reference and had a method to set the
reference to null.


Not true except for static references. If you held a direct reference
to the objects, then they would be collected when that reference were
to go out of scope. Static references, of course, never go out of
scope.


But that is exactly what you have - an object that never gioes out of scope
that holds direct references to delegates that hold direct references to
other objects.

[snip]
No - true memory leaks are impossible in .NET - the objects are
accessible
through the ItemDeleted event and hence are not leaks.


Sorry. I fail to see the difference between an object that is left
hanging around until your application terminates and a "true" memory
leak.


No - leaked memory is memory that you could never free even if you could be
bothered to write the code.

This memory has references to it.

It may seem different but actually it is no worse than:

static void Main()
{
byte[] b = new byte[100000000000000];
RunServer();
}

b is not leaked it is just inaccessible due to bad coding.
Weak references are a time/space trade off, no more and no less.


Not true. Weak references allow you to leave object disposal to the
garbage collector and concentrate on programming your application.
Using IDisposable, or some other disposal mechanism, requires that you
do proper memory housekeeping in order to avoid leaks (or, if you
prefer, "stuff not being garbage collected," which I maintain is
essentially the same thing). Weak references allow you to think about
static event subscribers in the same way you think about other objects
in your program: when they go out of scope, they "go away" (sooner or
later) and the memory they occupy is freed for reuse. Requiring
explicit disposal requires that you think about static event
subscribers differently: "This subscribes to a static event so I have
to explicitly dispose of it or it won't be GC'd."


WeakReferenced objects can be collected at ANY time.
They can become null sooner than you would want therefore you have to have a
way to reinstate them if they are null when you actually wanted the value
therefore they are merely a time space tradeoff.
Feb 16 '06 #16
If you google "Weak Event Handler" I think you will find that the one at the
top http://www.codeproject.com/csharp/we...lerfactory.asp works quite
nicely.

"Bruce Wood" wrote:
By the way, the "roll your own" code I posted was a response to
Googling "weak reference event handler" and finding several
(conflicting) examples of how to do it, none of which actually worked.
The code I posted, ugly as it is, and sadly pre-generics, _does_ work.
It not only provides for weak reference, but cleans up the event chain
as it discovers disposed client objects, if you choose to supply it
with a client when you subscribe.

The only thing I don't know is whether it deals "nicely" with
multithreading, so... caveat multeos threadus.

Feb 17 '06 #17

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by johny smith | last post: by
8 posts views Thread by Chris | last post: by
reply views Thread by Al | last post: by
14 posts views Thread by Gotch | last post: by
3 posts views Thread by nagashre | last post: by
6 posts views Thread by better_cs_now | last post: by
reply views Thread by rosydwin | last post: by

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.