473,385 Members | 1,353 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,385 software developers and data experts.

Events, weak references or other approach advice required

Hi, I've just written the following code to describe the issue I have.
In a nutshell if an object subscribes to an event on a long lived
object and I then ditch the reference to the subscriber (set it to
null) The object doesn't get GCed because the publisher still has a
reference to it.
Solutions I can think of are:
1) WeakReference - I'm not sure how to do that (Needs to be framework
1.1 and 2 compatible fyi) and I'd like to use events rather than
delegates directly if that makes sense.
2) Implement an interface to explicitly unsubscribe the subscribers
(Doesn't have to be an interface, just a method for simplicity) but
then I have to remember to call that. Not a huge hassle, and something
I already do in other applications.

Here's the code.

//Publisher first
-------------------------------------------------------
using System;
using System.Timers;

namespace Eventer
{
public delegate void TimerEventHandler(object sender, TimerEventArgs
e);
/// <summary>
/// Summary description for Publisher.
/// </summary>
public class Publisher
{
private Timer _timer=new Timer(2000);

public event TimerEventHandler TimerFired;

public Publisher()
{
_timer.Elapsed+=new ElapsedEventHandler(_timer_Elapsed);
_timer.Start();
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
TimerEventArgs nE=new TimerEventArgs(e.SignalTime.Ticks);
OnTimerFired(nE);
}
protected virtual void OnTimerFired(TimerEventArgs e)
{
if (null != TimerFired)
{
TimerFired(this,e);
}
}
}

public class TimerEventArgs : EventArgs
{
long _tick=0;

public TimerEventArgs(long pTick)
{
_tick = pTick;
}

public long Tick
{
get
{
return _tick;
}
}
}
}

// Subscriber
---------------------------------------------------------------------

using System;

namespace Eventer
{
/// <summary>
/// Summary description for Subscriber.
/// </summary>
public class Subscriber
{
int _value;

public Subscriber(int pValue, Publisher pPublisher)
{
_value = pValue;
pPublisher.TimerFired+=new TimerEventHandler(pPublisher_TimerFired);
}

private void pPublisher_TimerFired(object sender, TimerEventArgs e)
{
Console.WriteLine(_value.ToString() + " - " + e.Tick.ToString());
}
}
}

// The relevant bit of the form that tests it. Basically two buttons
one that starts and one that stops ------------------

private Publisher _publisber=new Publisher();
private System.Collections.ArrayList _arrayList=new ArrayList(5);

//Create subscribers
private void button1_Click(object sender, System.EventArgs e)
{
Subscriber s;

for(int c=0;c<5;c++)
{
s=new Subscriber(c,_publisber);
_arrayList.Add(s);
}

}

//clear reference to subscribers
private void button2_Click(object sender, System.EventArgs e)
{
_arrayList=null;
GC.Collect(); //trying to hurry things along for the demo
}

Sep 11 '06 #1
4 1539
One suggestion is to make the objects Disposable and then dispose them before
setting them to null. Then in the Dispose function you can un register them
from the event.
Ciaran O'Donnell

"DeveloperX" wrote:
Hi, I've just written the following code to describe the issue I have.
In a nutshell if an object subscribes to an event on a long lived
object and I then ditch the reference to the subscriber (set it to
null) The object doesn't get GCed because the publisher still has a
reference to it.
Solutions I can think of are:
1) WeakReference - I'm not sure how to do that (Needs to be framework
1.1 and 2 compatible fyi) and I'd like to use events rather than
delegates directly if that makes sense.
2) Implement an interface to explicitly unsubscribe the subscribers
(Doesn't have to be an interface, just a method for simplicity) but
then I have to remember to call that. Not a huge hassle, and something
I already do in other applications.

Here's the code.

//Publisher first
-------------------------------------------------------
using System;
using System.Timers;

namespace Eventer
{
public delegate void TimerEventHandler(object sender, TimerEventArgs
e);
/// <summary>
/// Summary description for Publisher.
/// </summary>
public class Publisher
{
private Timer _timer=new Timer(2000);

public event TimerEventHandler TimerFired;

public Publisher()
{
_timer.Elapsed+=new ElapsedEventHandler(_timer_Elapsed);
_timer.Start();
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
TimerEventArgs nE=new TimerEventArgs(e.SignalTime.Ticks);
OnTimerFired(nE);
}
protected virtual void OnTimerFired(TimerEventArgs e)
{
if (null != TimerFired)
{
TimerFired(this,e);
}
}
}

public class TimerEventArgs : EventArgs
{
long _tick=0;

public TimerEventArgs(long pTick)
{
_tick = pTick;
}

public long Tick
{
get
{
return _tick;
}
}
}
}

// Subscriber
---------------------------------------------------------------------

using System;

namespace Eventer
{
/// <summary>
/// Summary description for Subscriber.
/// </summary>
public class Subscriber
{
int _value;

public Subscriber(int pValue, Publisher pPublisher)
{
_value = pValue;
pPublisher.TimerFired+=new TimerEventHandler(pPublisher_TimerFired);
}

private void pPublisher_TimerFired(object sender, TimerEventArgs e)
{
Console.WriteLine(_value.ToString() + " - " + e.Tick.ToString());
}
}
}

// The relevant bit of the form that tests it. Basically two buttons
one that starts and one that stops ------------------

private Publisher _publisber=new Publisher();
private System.Collections.ArrayList _arrayList=new ArrayList(5);

//Create subscribers
private void button1_Click(object sender, System.EventArgs e)
{
Subscriber s;

for(int c=0;c<5;c++)
{
s=new Subscriber(c,_publisber);
_arrayList.Add(s);
}

}

//clear reference to subscribers
private void button2_Click(object sender, System.EventArgs e)
{
_arrayList=null;
GC.Collect(); //trying to hurry things along for the demo
}

Sep 11 '06 #2
try this:

System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\test.xml");
System.Xml.XmlTextWriter xtr = new System.Xml.XmlTextWriter(file);
xtr.Formatting = System.Xml.Formatting.Indented;
ser.Serialize(xtr, test);
file.Flush();
file.Close();
Ciaran O'Donnell
"DeveloperX" wrote:
Hi, I've just written the following code to describe the issue I have.
In a nutshell if an object subscribes to an event on a long lived
object and I then ditch the reference to the subscriber (set it to
null) The object doesn't get GCed because the publisher still has a
reference to it.
Solutions I can think of are:
1) WeakReference - I'm not sure how to do that (Needs to be framework
1.1 and 2 compatible fyi) and I'd like to use events rather than
delegates directly if that makes sense.
2) Implement an interface to explicitly unsubscribe the subscribers
(Doesn't have to be an interface, just a method for simplicity) but
then I have to remember to call that. Not a huge hassle, and something
I already do in other applications.

Here's the code.

//Publisher first
-------------------------------------------------------
using System;
using System.Timers;

namespace Eventer
{
public delegate void TimerEventHandler(object sender, TimerEventArgs
e);
/// <summary>
/// Summary description for Publisher.
/// </summary>
public class Publisher
{
private Timer _timer=new Timer(2000);

public event TimerEventHandler TimerFired;

public Publisher()
{
_timer.Elapsed+=new ElapsedEventHandler(_timer_Elapsed);
_timer.Start();
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
TimerEventArgs nE=new TimerEventArgs(e.SignalTime.Ticks);
OnTimerFired(nE);
}
protected virtual void OnTimerFired(TimerEventArgs e)
{
if (null != TimerFired)
{
TimerFired(this,e);
}
}
}

public class TimerEventArgs : EventArgs
{
long _tick=0;

public TimerEventArgs(long pTick)
{
_tick = pTick;
}

public long Tick
{
get
{
return _tick;
}
}
}
}

// Subscriber
---------------------------------------------------------------------

using System;

namespace Eventer
{
/// <summary>
/// Summary description for Subscriber.
/// </summary>
public class Subscriber
{
int _value;

public Subscriber(int pValue, Publisher pPublisher)
{
_value = pValue;
pPublisher.TimerFired+=new TimerEventHandler(pPublisher_TimerFired);
}

private void pPublisher_TimerFired(object sender, TimerEventArgs e)
{
Console.WriteLine(_value.ToString() + " - " + e.Tick.ToString());
}
}
}

// The relevant bit of the form that tests it. Basically two buttons
one that starts and one that stops ------------------

private Publisher _publisber=new Publisher();
private System.Collections.ArrayList _arrayList=new ArrayList(5);

//Create subscribers
private void button1_Click(object sender, System.EventArgs e)
{
Subscriber s;

for(int c=0;c<5;c++)
{
s=new Subscriber(c,_publisber);
_arrayList.Add(s);
}

}

//clear reference to subscribers
private void button2_Click(object sender, System.EventArgs e)
{
_arrayList=null;
GC.Collect(); //trying to hurry things along for the demo
}

Sep 11 '06 #3
Hi,
"DeveloperX" <nn*****@operamail.comwrote in message
news:11**********************@i42g2000cwa.googlegr oups.com...
Hi, I've just written the following code to describe the issue I have.
In a nutshell if an object subscribes to an event on a long lived
object and I then ditch the reference to the subscriber (set it to
null) The object doesn't get GCed because the publisher still has a
reference to it.
Solutions I can think of are:
1) WeakReference - I'm not sure how to do that (Needs to be framework
1.1 and 2 compatible fyi) and I'd like to use events rather than
delegates directly if that makes sense.
Not sure how (if) this will work.
2) Implement an interface to explicitly unsubscribe the subscribers
(Doesn't have to be an interface, just a method for simplicity) but
then I have to remember to call that. Not a huge hassle, and something
I already do in other applications.
I think this is the way to go with a twist, instead of a new interface you
could implement IDisposable and do your "cleaning" in the Dispose method.

You object will need a list of the subscriptions he did during its lifetime
and just unsubscribe from them. Not a terrible difficilt thing to implement
I think.

--
--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Sep 11 '06 #4

Ignacio Machin ( .NET/ C# MVP ) wrote:
Hi,
"DeveloperX" <nn*****@operamail.comwrote in message
news:11**********************@i42g2000cwa.googlegr oups.com...
Hi, I've just written the following code to describe the issue I have.
In a nutshell if an object subscribes to an event on a long lived
object and I then ditch the reference to the subscriber (set it to
null) The object doesn't get GCed because the publisher still has a
reference to it.
Solutions I can think of are:
1) WeakReference - I'm not sure how to do that (Needs to be framework
1.1 and 2 compatible fyi) and I'd like to use events rather than
delegates directly if that makes sense.

Not sure how (if) this will work.
2) Implement an interface to explicitly unsubscribe the subscribers
(Doesn't have to be an interface, just a method for simplicity) but
then I have to remember to call that. Not a huge hassle, and something
I already do in other applications.

I think this is the way to go with a twist, instead of a new interface you
could implement IDisposable and do your "cleaning" in the Dispose method.

You object will need a list of the subscriptions he did during its lifetime
and just unsubscribe from them. Not a terrible difficilt thing to implement
I think.

--
--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation
Yep, I use an interface as I wrap up registering and unregistering in
the same place. The event thing just suprised me for some reason, I'm
suprised I've not noticed it in the past, but I guess it doesn't
necessarily come up that often.
I'm as likely to register the subscribers with the publisher and have
the publisher call methods on the subscribers. Same issue of course,
Publisher holds a reference to the subscriber, but there you go.

Sep 11 '06 #5

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

Similar topics

12
by: scsharma | last post by:
Hi, I am working on creating a webapplication and my design calls for creating main webform which will have menu bar on left hand side and a IFrame which will contain all the forms that are shown...
4
by: Dean Slindee | last post by:
Is there a shorter way of referring to another forms controls/events than creating a class hold forms, adding a form item each time a new form is loaded, and then looping thru the class of forms to...
9
by: Olivier Fermy | last post by:
I have created a sample project where i have referenced an object only with an event : textBox.VisibleChanged += new EventHandler(this.textBox_VisibleChanged); When i call GC.Collect(), the...
16
by: anonymous.user0 | last post by:
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...
30
by: Burkhard | last post by:
Hi, I am new to C# (with long year experience in C++) and I am a bit confused by the language construct of events. What is it I can do with events that I cannot do with delegates? At the moment...
5
by: Daniel | last post by:
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...
5
by: Aleksey | last post by:
Hi all! It's a theoretical question. Suppose I have object A with event OnAction and I have object B that connects to this event. I create object B as a local method variable and in this method I...
11
by: MikeT | last post by:
This may sound very elementary, but can you trap when your object is set to null within the object? I have created a class that registers an event from an object passed in the constructor. When...
1
by: Henri.Chinasque | last post by:
Hi all, I've been considering that my objects should subscribe to an event via a weak reference, however I've found several warnings that this approach comes with concurrency considerations,...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
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...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
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...

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.