Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does CLR say that an object has a finalizer?

I know that in C#, if you write ~MyClass(), this basically translates to override System.Object.Finalize(). So, whether you write the destructor or not, every type in CLR will have a Finalize() method in it (of System.Object at least).

1] So, does it mean that, every object, by default, has a finalizer ?

2] What is the basis for the CLR to decide that an object should be put through finalization queue ?

I'm asking this, because, I had a class, say ManagedResourceHolder that implemented IDisposable, but did not call GC.SuppressFinalize(this) in its IDisposable.Dispose() method. The class did not hold any unmanaged resources, and there was no need for the ~ManagedResourceHolder() method, which in turn meant no need for the GC.SuppressFinalize(this) call as there was no finalizer.

3] In context of the above scenario, is it always necessary to provide a finalizer when you implement IDisposable ? (even on a class that holds no unmanaged resources)

The FxCop rule CA1816 was giving me a violation on this and the response I got here when I asked in the CA forum on MSDN confused me.

Thanks.

like image 849
mherle Avatar asked Dec 11 '08 08:12

mherle


2 Answers

Questions 1 and 2: The CLR basically checks whether or not the finalizer is overridden. If it's not, it treats it as not having a finalizer.

The benefit of having a finalizer in System.Object is that compilers know they can always put a call to base.Finalize() in. This avoids versioning issues. Consider a world without System.Object.Finalize():

  • System.Object (no Finalize)
  • Acme.BaseClass (no Finalize)
  • MyCompany.DerivedClass (Finalize)

Without a Finalize method in object, the finalizer in MyCompany.DerivedClass can't call anything. Which leads to a problem when version 2 of Acme.BaseClass comes out with a finalizer. Unless you recompile MyCompany.DerivedClass, an instance of DerivedClass will be finalized without calling BaseClass.Finalize, which is clearly a Bad Thing.

Now consider the same situation with System.Object.Finalize - the compiler inserts a call to base.Finalize automatically in DerivedClass.Finalize, which in version 1 just calls the no-op implementation in System.Object. When version 2 of Acme.BaseClass comes out, the call to base.Finalize will (without recompilation of DerivedClass) call BaseClass.Finalize.

Question 3: No, you don't need to have a finalizer just because you implement IDisposable. Finalizers should only be used for unmanaged resources which nothing else is going to clean up - i.e. ones you have a direct reference to. For instance, suppose you have a class which has a FileStream member variable. You want to implement IDisposable so you can close the stream as soon as possible, if the caller remembers - but if they don't remember to call Dispose(), the stream will become eligible for garbage collection at the same time as your object. Trust that FileStream has an appropriate finalizer (or a reference to something else with a finalizer etc) rather than trying to clean it up in your own finalizer.

As of .NET 2.0, with the SafeHandle class, it should be incredibly rare for you to need your own finalizer.

like image 61
Jon Skeet Avatar answered Nov 19 '22 18:11

Jon Skeet


1: It only really counts (in the useful sense) if it has been overridden

2: As defined by 1, and GC.SuppressFinalize has not been called (plus re-register etc)

3: certainly not; in fact, unless you are directly handling an unmanaged resource, you shouldn't have a finalizer. You shouldn't add a finalizer just because it is IDisposable - but things that have finalizers should also generally be IDisposable.

like image 29
Marc Gravell Avatar answered Nov 19 '22 20:11

Marc Gravell