简体   繁体   中英

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.

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 - ie 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.

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.

  1. Nope, it doesn't mean so. Only overridden Finalize() will count by the CLR.
  2. By having a finalizer, as defined above.
  3. Nope, it's not necessary. 必要的。 It's just a nice pattern. I mean, nobody forces you to do so. But it's a good thing to do if you have unmanaged resources, since if somebody forgets to dispose it, the unmanaged resource will get released sometime. FxCop does not enforce strict rules. It enforces good patterns that may lead to failure in the future if you don't take care of.

UPDATE: Every class is responsible for managing its own resources. Due to abstraction and encapsulation features of object-oriented paradigms, the consumer of a class should not care about what resources it has, indirectly. Therefore, you should either manually release the resources you own (what you own is what you as you look at other things as a ) or leave it to the GC to release them. 的资源)或将其留给GC以释放它们。 For unmanaged resources, you don't have the option to leave it to the GC, so you have to release it manually. In this sense, a SafeHandle that Jon mentioned is a , therefore it should be treated as a valuable managed resource (which is a black box that manages the finalization of that unmanaged resource itself). ,因此它应被视为有价值的托管资源(这是一个黑盒子,用于管理非托管资源本身的最终化)。

1) Yes (by virtue of inheritance)

2) Nothing is holding a reference to the instance of a class (that will make it eligible for finalization)

3) Yes (why should one implement IDisposable unless it is requiring the user to explicitly call dispose? Connection classes in .net use an umanaged resource under the hood & if you don't call dispose on it, it will hang on to it. Since the GC timing is unknown, the connection will remain open till that time)

This is my understanding.

I could be wrong. In which case, experts will correct things out for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM