0

Background:

I've a got a main object that live on my app's UI thread. This long-lived parent / container object contains a sub-object as a private member that is internally multi-threaded.

Based on some event published from the child / contained object I'd like the parent object to simply Dispose() the child and recreate it.

The contained object owns some unmanaged resources and well as some large managed memory buffers.

I could create an event handler on the top level object that does this, but this means that the object about to be Disposed will be in the call stack of the method call to about to replace it. (!)

This is because the event handler delegate will be called by one of the child object's state handling functions on it's own thread.

This seems...wrong. No?

In particular, the the child's FireAnEvent() method will resume execution after the delegate calls are processed, except that now execution will resume in the context of an already "disposed" object.

Intuitively, I can't see this leading to good things.

Question:

Is there an established C# pattern to destroy a contained object as a result of it's own event?

Or, is there GC magic that makes such a simple event handler good enough somehow?

Or, am I missing some key bit of understanding?

ddl877
  • 43
  • 5
  • are the child objects short lived, as opposed to the long lived parent? And by parent and child do you mean class and subclass, or container and contained? – Assaf Sep 19 '14 at 00:43
  • May be you need to create some thread control logic that will terminate threads once your child detects that it needs to be terminated. Or move your child into separate process. Then, terminating this child will mean destruction of all threads in that process, as long as you marked them as `background`. http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground%28v=vs.110%29.aspx – T.S. Sep 19 '14 at 00:44
  • This is subjective. If there's a C# pattern at all then consider that none of the Microsoft components have a "you can only call Dispose() if this and that event isn't fired" manual page. It is an *unwise* thing to do, you normally can't be sure that the programmer considered the possibility. Of course that's not your problem, you can easily test it and the fix is easy. If you hate the idea then consider the alternative, you can always BeginInvoke() to get the Dispose call performed later. A nicety of dispatcher loops :) – Hans Passant Sep 19 '14 at 01:11
  • @Assaf Question clarified. Yes, just a contained object within a long lived container, no OO inheritance. – ddl877 Sep 19 '14 at 16:54

3 Answers3

1

Calling IDisposable.Dispose() doesn't signal anything special to the .NET framework. The only thing you need to do is remove any references to the object you wish to remove. Once this is done and the object is out of the call stack, it will become a candidate for garbage collection.

Note that your object will not necessarily be garbage collected immediately, or even the next time the GC runs; it is merely an assumed eventuality.

The only purpose of IDisposable is to provide a standard means for requesting that an object clean itself up and release resources. You can hold a reference to a "disposed" object for as long as you like, which will prevent the GC from collecting the object. IDisposable.Dispose() is just another method; technically, you can make it do anything you want.

This question has a very nicely detailed answer that may help you understand IDisposable a bit more: Proper use of the IDisposable interface

Community
  • 1
  • 1
Taudris
  • 1,413
  • 1
  • 15
  • 23
  • Thank for the answer, I've updated the question to clarify slightly. I understand that `Dispose()` is intended to free non-clr resources and that GC delete may not happen for a while. The issue is that objects that I've seen don't expect to be used after a `Dispose()` was called on them. Yet, here we'd be resuming execution in an object whose underlying resources had been freed already. – ddl877 Sep 19 '14 at 16:59
  • Then you either need to guarantee that it's safe to call `Dispose()` at the time you fire the event, or you need a solution that gets the object out of the call stack before `Dispose()` is called. The latter can be done in a myriad of ways. Since this is a single sub-object, you could set a flag on the parent, and dispose of it later using any of Hans Passant's suggestion of `BeginInvoke()`, queuing a task, having a thread block on an event and signal the event, and probably many others. Just make sure that you avoid creating a race condition. – Taudris Sep 20 '14 at 00:43
0

as mentioned, an IDisposable object is nothing magical. It just lets you use the using shorthand, which is just a shorthand for:

try { // code in the using block }
catch{}
finally{
    disposableObject.Dispose()
}

Have you considered incorporating a third type of object into the mix? It is ill advised that contained object be conscious of their container. Roughly this would be your workflow:

  1. contained object decides it should be restarted.
  2. contained object frees resources.
  3. contained object writes to a queue on a third object (not the containing object).
  4. containing object accesses the queue when you feel you should create new contained objects and reinstantiates the objects. Alternatively adding to the queue raises an event to the container to empty it.

The third object might seem pointless but it would make your life a lot easier if you ever decided to refactor.

Assaf
  • 1,352
  • 10
  • 19
0

Objects which subscribe to events for the purpose of notification should be prepared to receive notifications at any time, even after they have been disposed. The purpose of a notification is to tell an object to do whatever it needs to do in response to something that has happened. If an object can't do anything useful in response to a notification, it should simply not do anything.

Further, the purpose of Dispose isn't to "destroy" an object, nor the resources it contains, but rather to release it from any obligations it may have had to outside objects, and allow it to release any outside entities from any obligations they might have had toward it. In many cases, an object will be useless once it releasing the services of outside entities that were committed to it, and thus objects which have been disposed cannot be expected to be useful; if, as is likely, a method which is called after Disposed cannot satisfy its duties because necessary outside entities have been released, it should throw ObjectDisposedException rather than failing some other way.

Putting these observations together, while many methods on a disposed object should throw ObjectDisposedException, notification event handler methods should not, since they're instructing the object to "do whatever you need to do to meet your obligations, given that something has happened". If an object has been disposed, it has no obligations. Thus, being disposed doesn't prevent an object from satisfying an event handler contract; instead, it allows the object to meet the contract by silently ("successfully") doing nothing.

supercat
  • 77,689
  • 9
  • 166
  • 211