Using the Destructor/Dispose of the base class?
Asked Answered
P

4

9

In C#, as mentioned in the Documentation, and this nice post's accepted answer, it's stated that classes don't inherit the Destructor of their parent class.

The question : If I want to make sure to dispose the private elements of the base class, is the proper way to implement IDisposable in all the child class, and in the Dispose method, call base.Dispose()?

It looks alright to do so, but I would have preferred a way which wouldn't require implementation in all of the child classes.

Profane answered 20/4, 2011 at 14:48 Comment(10)
Please only do this if your "private elements" are unmanaged resources.Jereme
@Henk: Whether or not the "private elements" of the base class are unmanaged is an implementation detail that the child classes shouldn't really care about. If your base class implements IDisposable then it should be disposed.Free
In this case, the private elements of the base class are indeed unmanaged resources, but as LukeH said, the child classes are not 'aware' of this.Profane
@lukeh: implementing IDisposable and having to be Disposed are separate from having (needing) a destructor.Jereme
@LukeH: If a class or its parent class implements a finalizer, then it and all derived classes will likely have to use GC.KeepAlive in many cases that would not otherwise be necessary (or else risk random failures). This is not a private "implementation detail". If .net provided a means of tagging a class in such a way as to require the jitter to always regard "self" as live, the issue of finalization might be abstracted away, but I'm unaware of any such means.Fleer
@supercat: I'm not really sure what you mean. Do you have an example and/or more details of how one of these "random failures" might occur?Free
@LukeH: Suppose a class holds an unmanaged handle to a Widget (a plug-in device), and method WriteData, as its very last action, calls SendDataToWidget(widgetHandle, DataToSend). If the class does not have a finalizer and it gets abandoned, the widget may be left in an unusable state (unless or until it times out or something), but the behavior will be deterministic. If an object (e.g. Fred) has a finalizer, though, a problem can occur if the code that holds the last reference to Fred calls Fred.WriteData before abandoning it. Fred would become eligible for garbage collection...Fleer
@LukeH: ...as soon as it calls SendDataToWidget()--before that call returns. Consequently, the garbage collector could end up executing the finalizer for Fred, killing off the widget specified by widgetHandle, while the SendDataToWidge operation was still in progress.Fleer
@supercat: Surely the call to KeepAlive would only need to be inside the WriteData method, immediately following the call to SendDataToWidget. Any subclasses or call sites wouldn't need to be aware of this, or would they?Free
@LukeH: Anything that makes use of part of the object which will be invalidated by the finalizer but does not hold a reference to the object as a whole will need a KeepAlive. In some cases, it's possible for all the KeepAlive stuff to be in the parent class, but in some cases the child class may need one.Fleer
D
16

MSDN states that destructors are called on base classes automatically.

Demeanor answered 20/4, 2011 at 14:52 Comment(1)
Thanks Nik! I should have read further than "Destructors cannot be inherited or overloaded."Profane
J
7

You should follow the Disposable pattern here. It also caters for inheritance.

The interesting part here is "destructors don't inherit", I'm not sure what to make of that. I wrote a little test but to my relief you only need to write a destructor in the base-class.

So the children are uncoupled from the base-class unmanaged resources. They can override Dispose(bool) to cleanup their own affairs.

But I made a comment because I see too many programmers implementing the full pattern just to handle managed resources.

From a general design perspective, a Disposable class would better be sealed.

Jereme answered 20/4, 2011 at 15:23 Comment(1)
Thanks Henk. I'll compare the pattern you linked with what I've done, and make the needed adjustment, just for the sake of correctness! :-DProfane
L
0

The base class should use the standard IDisposable pattern for base classes - in this way only the base class needs a finalizer, and derived classes simply override the virtual method

protected void Dispose(bool disposing)
Lavolta answered 20/4, 2011 at 15:25 Comment(0)
F
0

If the parent class uses Microsoft's IDisposable pattern, the child class should not override Dispose(void) but instead override Dispose(Boolean Disposing). If called with Disposing true, it should dispose the child class and call base.Dispose(True). If called with Disposing false, it should in most cases no nothing except call base.Dispose(False).

Note that in most cases, the call to base.Dispose(False) will do nothing, but it should be made anyway. If the child class would need to add additional "unmanaged resources" (i.e. if it has additional responsibilities that need to be performed in a finalizer) it should generally encapsulate those responsibilities into another object. Note that the question of whether a class has a finalizer is not just an "implementation detail"; adding a finalizer to a base class can be a breaking change, causing a program which would have leaked resources (bad, but perhaps survivable if it the program isn't run for too long at a time) into one which will, on random occasions, attempt to clean up resources which are still in use (won't often cause problems, but may cause rare but immediate failures).

Fleer answered 20/4, 2011 at 15:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.