Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / September 2007

Tip: Looking for answers? Try searching our database.

Event handler not responding on new instance of class

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Mike Thompson - 24 Sep 2007 20:17 GMT
The language for this question is C#.

I have a class named client which derives from IDisposable; it contains
several event handlers.

In another class, I create a static instance of the client class and
subscribe to two of its events, using standard += syntax, for example:

client.Error += new EventHandler<client.ErrorEventArgs>(client_ErrorEvents);

Later in code, I unsubscribe from the events (for example client.Error -=
client_ErrorEvents;), and dispose of the instance of the client class by
calling its Dispose method:

       public void Dispose()
       {
           Dispose(true);
           GC.SuppressFinalize(this);
       }

Now, without closing the main form, I create a new instance of the client
class (this is a button click event).  Its methods and properties are
available again as before, but its event handers do not respond to any
events this time, although they responded the first time.

This a multithreaded environment, but I don't think that is causing any
problems in this case.

I hope this is enough code to illustrate the problem.  Any ideas would be
most appreciated.
Mattias Sjögren - 24 Sep 2007 21:37 GMT
Mike,

>I hope this is enough code to illustrate the problem.  Any ideas would be
>most appreciated.

Not for me it isn't - not enough information here to reproduce the
problem. Can you post a more complete sample?

Mattias

Signature

Mattias Sjögren [C# MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Mike Thompson - 25 Sep 2007 15:36 GMT
This is a big project, so I'll post the relevant code sections.

   public partial class Connection
   {

       public static ZClient client = new ZClient();

       public static string DataRequest(int Call)
       {
           client.DataEvent += new
EventHandler<ZClient.TickPriceEventArgs>(client_Data);

           [MORE CODE]
       }

       public static string Destroy (Form1 frm)
       {

           string Result = "Disconnected";

           try
           {
               client.DataEvent -= client_DataEvent;
               client.Disconnect();
               client.Dispose();
           }

           catch (Exception e)

           {
               Result = e.ToString();
           }

           return Result;
       }

   }

The event handlers are declared in the ZClient class:

       public event EventHandler<DataEventArgs> DataEvent;

       protected virtual void OnData (DataEventArgs e)
       {
           if (Data != null)
               Data (this, e);
       }

       private void Data(int A, B, C, double D, bool E)
       {
           DataEventArgs e = new DataEventArgs(A, B, D, E);
           OnData (e);
       }

So the Connection class contains a static instance of ZClient, and the
DataRequest method subscribes to an event.  The Destroy method unsubscribes
to the event, then disposes of the object instance of the client object.

The object has now been completely disposed of.  But on a new call to
DataRequest, the methods of the ZClient class are available again (using an
instance called client), but the events are not.

It looks like this is not a new instance of the ZClient object, because the
first instance was destroyed, and it's a static member of the Connection
class.  Why then are the methods available once again, but the events not?

Thanks again for any help.

> Mike,
>
[quoted text clipped - 5 lines]
>
> Mattias
Peter Duniho - 25 Sep 2007 19:36 GMT
> [...]
> So the Connection class contains a static instance of ZClient, and the
> DataRequest method subscribes to an event.  The Destroy method unsubscribes
> to the event, then disposes of the object instance of the client object.

And where do you create a new instance?

As near as I can tell, your static member "client" continues to
reference the original instance that was created as part of the static
initialization of the class.  But since you've called Dispose() on it,
it would not surprise me that later uses of it wouldn't work correctly.

> The object has now been completely disposed of.  But on a new call to
> DataRequest, the methods of the ZClient class are available again (using an
> instance called client), but the events are not.

If the events are raised by code that depends on some data within
ZClient that is released when you call Dispose(), then those events
might not be able to be raised on a disposed object.

> It looks like this is not a new instance of the ZClient object, because the
> first instance was destroyed, and it's a static member of the Connection
> class.  Why then are the methods available once again, but the events not?

I agree that it doesn't seem like this is a new instance.  Note that the
original instance is only "destroyed" in the sense that you've called a
method that you named "Destroy".  The object itself exists for as long
as the reference exists, and you can use that reference to call any
instance method on the class.

I'm not sure whether C# allows this or not, but in fact it's not even
strictly required that the reference be valid unless you are calling a
virtual method.  In C++ for example, you could call a non-virtual
instance method using a null value, and the method would be executed as
usual, except that the "this" reference in the method would be null.

Without seeing the code that actually raises the events and without
knowing what gets disposed when you call Dispose() on your ZClient
class, it's not really possible to say exactly what's going wrong.
However, what _is_ apparent from the code you posted is that you are
trying to use an object that's been disposed, and that's definitely not
a good thing.  :)

IMHO, I'm not really even sure that it's a good idea to design your
class the way you have.  You seem to be treated it effectively as an
instantiated object, but using a static member, and that seems likely to
lead to other bugs as well.

However, assuming you really want this design, you'll need to make sure
that you have consistent rules for how to use the ZClient class, and
then follow those rules.  At the very least, you should probably create
a new instance in the Destroy method, right after you call Dispose() on
the old instance; that would be the smallest change that from the code
you posted would seem to fix the basic problem.

Pete
Mike Thompson - 25 Sep 2007 20:33 GMT
I declared it as a static class object so the same instance would be
available to all methods in the class.  I can't create a new instance of the
object each time I use it, because each object created with the "new"
keyword is a separate object.  Functions performed on a non-static instance
would apply only to that instance.  The ZClient class is the heart of the
entire program; it can't be instantiated as new for each function that needs
to use it.

> At the very least, you should probably create a new instance in the
> Destroy method, right after you call > Dispose() on the old instance

The problem with that approach is that the new instance would be accessible
only in the Destroy method, not anywhere else.  This would lead to the
problem of having multiple instances of the same object, which would cause
other problems.

As far as the static approach leading to other bugs, everything else has
worked fine.  But the error handlers seem to die when I use the Dispose
method of IDisposable (remember that the ZClient class derives from
IDisposable), even though they are explicitly un-subscribed, then
re-subscribed to.

I appreciate your comments.  This issue may be too obscure for anyone not
directly involved with all of the code.  I hope I can solve it.

>> [...]
>> So the Connection class contains a static instance of ZClient, and the
[quoted text clipped - 55 lines]
>
> Pete
Peter Duniho - 25 Sep 2007 21:41 GMT
> I declared it as a static class object so the same instance would be
> available to all methods in the class.  

I do understand the purpose of using a static member.  My point is that
if you have a situation where that instance may be destroyed by some
code somewhere, before all other code that might want to use it is
actually done with it, then I'm not convinced that's a wise design.

> I can't create a new instance of the
> object each time I use it, because each object created with the "new"
> keyword is a separate object.  

I certainly never suggested doing that.  But you could create a new
instance for each different "client" of the class.  That is, where you
have a situation in which some area of your code may be done with the
object and want to call the Destroy method, but you have some other area
of your code that will later want to use the object, that's a pretty
clear division of two parts of code that do not necessarily need to be
using the same instance (and in fact possibly should not be).

I admit, without seeing the full design (and no, I'm not asking to see
the full design) it's impossible to say for sure.  I'm just sharing some
general rules of thumb that can be used to evaluate the correctness of a
particular design choice.

> Functions performed on a non-static instance
> would apply only to that instance.  The ZClient class is the heart of the
> entire program; it can't be instantiated as new for each function that needs
> to use it.

Then why is it disposed before your application is done?

>> At the very least, you should probably create a new instance in the
>> Destroy method, right after you call > Dispose() on the old instance
[quoted text clipped - 3 lines]
> problem of having multiple instances of the same object, which would cause
> other problems.

Um, no.  Obviously the instance you create would be assigned to the
"client" member, causing the disposed one to be eligible for garbage
collection and the new one to be used by code executing subsequently.

You don't mention if your application is threaded; if so you should
synchronize access to the member.  But this is true even if you don't
change anything else.

> As far as the static approach leading to other bugs, everything else has
> worked fine.  But the error handlers seem to die when I use the Dispose
> method of IDisposable (remember that the ZClient class derives from
> IDisposable), even though they are explicitly un-subscribed, then
> re-subscribed to.

ZClient doesn't "derive from" IDisposable.  It implements it.  You
haven't explained what that implementation of Dispose() method does
(required for classes that implement IDisposable), but it seems likely
to me that it does something that breaks the ability to use the event.

It's not really clear to me why you're expecting the ZClient class to be
usable after it's been disposed.  I'm not aware of any specific rule
that says you can't, but the class would have to be specifically
designed to handle that and would have to explicitly document this as
its behavior.  Barring that, you should assume that once you've disposed
an object, it's not usable.  Just because you can call the methods in
the class, that doesn't mean it's usable.

Pete
Jon Skeet [C# MVP] - 24 Sep 2007 22:28 GMT
> The language for this question is C#.
>
[quoted text clipped - 3 lines]
> In another class, I create a static instance of the client class and
> subscribe to two of its events, using standard += syntax, for example:

There's no such thing as a "static instance". Do you mean you happen to
be storing a reference to the new object in a static variable?

> client.Error += new EventHandler<client.ErrorEventArgs>(client_ErrorEvents);
>
[quoted text clipped - 12 lines]
> available again as before, but its event handers do not respond to any
> events this time, although they responded the first time.

Presumably you haven't subscribed to the events of the new object. Each
instance will have separate event handlers, unless the events
themselves are static.

Signature

Jon Skeet - <skeet@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


Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.