I've looked in SO about a question like this one, and even that I've found quite a few, any of those threw any light into this matter for me.
Let's assume I have this code:
public class SuperObject : IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) { }
}
protected virtual void Dispose(bool)
on SuperObject
? Since there is really nothing to dispose there.public interface ICustom : IDisposable { }
public class Custom : ICustom
{
public SuperObject Super { get; protected set; }
public Custom()
{
Super = new SuperObject();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposing)
{
if (!disposing) return;
if (Super != null)
Super.Dispose();
}
}
public class Foo
{
public Foo()
{
using (var c = new Custom())
{
//do magic with c
}
}
}
Now what happens if I want/need/try to use Custom
on a class like System.Web.Mvc.Controller
which already implements and has implemented IDisposable?
public class Moo : Controller
{
Custom c;
public Moo()
{
c = new Custom();
}
// Use c throughout this class
}
How to properly dispose c
in Moo
?
The normal approach is to apply the standard IDisposable implementation - HOWEVER this is really only necessary if your class or some class that derives from it will use UNmanaged resources - this case is infact VERY rare (and when this case does apply it is better to wrap the unmanaged resource in its own class that has a full standard IDisposable implementation).
So assuming you are not dealing with UNmanaged resources (raw file handles, globally alloced memeory etc) and are only dealing with members that are disposable (i.e that have managed resources and implement IDisposable) then you can safely get a way with a mimimal implimentation of IDispose - that is:
Just have a single void Dispose() method. In that method just call dispose on dispoable members and then Dispose on the base class if its disposable. If you have a class hierachy its ok to make this Dispose virtual. There is no need to have a Dispose(bool) method. Nor is there any need to check if the object is disposed - because all your doing is calling dipsose on other objects and those implementation will do that check.
If you don't like the mimimal appraoch then apply the standard full implimentation (but it is not strictly necessary). I.e either do a standard implimentation because your a stickler for following the recommended approach OR do a simple minimal (but correct) implementation - but don't do something in between (i.e not standard, not simple or not correct)!
See this question for more details: Minimal IDispose implimenation for managed resources only
So in your case the following is the mimimal implimentation:
public class SuperObject : IDisposable {
public void Dispose() {
// Dispose code...just call dispose on dispoable members.
// If there are none then no need to implement IDisposable!
}
}
public interface ICustom : IDisposable { }
public class Custom : ICustom {
public SuperObject Super { get; protected set; }
public Custom() {
Super = new SuperObject();
}
public void Dispose() {
if (Super != null)
Super.Dispose();
}
}
public class Moo : Controller {
Custom c;
public Moo() {
c = new Custom();
}
public Dispose() {
if (c!=null)
c.Dispose()
base.Dispose();
}
}
Note that if Super object does not have any disposable resources then there is no point in implementing IDisposable and having a Dispose method. If Customs only disposable object is SuperObject then the same applies there, and again the same logic rocks through to Moo. Finally then if all the above applies and there are no other disposable objects around all you need really need is:
public class Moo : Controller {
Custom c;
public Moo() {
c = new Custom();
}
public Dispose() {
base.Dispose();
}
}
How to properly dispose
c
inMoo
?
public class Moo : Controller
{
Custom c;
public Moo()
{
c = new Custom();
}
// Use c throughout this class
protected override Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
c.Dispose()
}
}
And that also answers your first question, Controller
needs to make its Dispose(bool)
method protected virtual
or the above would not be possible.
But a few notes:
isDisposed
logic. It is a good idea to do the disposing only once, and you may want to trap usage-after-dispose. If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With