Specific Questions About C # Dispose Pattern

I have some basic questions about Dispose Pattern in C #.

In the next code snippet, which appears to be the standard way to implement the deletion template, you will notice that managed resources are not processed if the disposal is false. How and when are they processed? Can the GC come and process the managed resources later? But if so, what does the call to GG.SuppressFinalize (this) do? Can someone give me an example of disposing of managed resources? There is a denouement of events. Anything else? The way of writing the pattern, it seems that they will be deleted (later) if you did not do anything in the "if (order)" section. Comments?

protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Dispose managed resources. } // There are no unmanaged resources to release, but // if we add them, they need to be released here. } disposed = true; // If it is available, make the call to the // base class Dispose(Boolean) method base.Dispose(disposing); } // implements IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } 

It is true that I read about locks in Dispose (bool) in this thread. How to implement a dispose pattern in C # when wrapping an Interop COM object? ? It says: "Meta-meta-comment - it’s also important that you never acquire locks or use locks during your unmanaged cleanup." Why is this? Does this apply to unmanaged resources?

Finally, does an implementation of the finalizer (~ MyClass () in C #) ever do without the implementation of IDisposable? I believe I read somewhere that finalizers and IDisposable are not needed (or desirable) if there are no unmanaged resources. However, in some examples, I see the use of a finalizer without IDisposable (see http://www.codeproject.com/KB/cs/idisposable.aspx for an example) Thanks, Dave

+7
c # idisposable dispose
source share
7 answers

This way of implementing the IDisposable template is a fault-tolerant way: if the client forgot to call Dispose , the finalizer called by the runtime will call Dispose(false) later (note that this part is missing from your sample).

In the latter case, i.e. when Dispose is called by the finalizer, the managed resources will already be cleared, because otherwise the object in question would not have the right to garbage collection.

But if so, what does the GC.SuppressFinalize (this) call do?

Running the finalizer comes at an additional cost. Therefore, it should be avoided if possible. Calling GC.SuppressFinalize(this) skip the finalizer, and therefore the object can be assembled more efficiently.

In general, the use of finalizers should be avoided since there is no guarantee that the finalizer will work. Some problems with finalizers are described by Raymond Chen in the following post:

When do I need to use GC.KeepAlive?

+5
source share

No one got to the last two questions (by the way: I ask only one per thread). Using lock in Dispose () is pretty deadly for the finalizer thread. There is no upper bound on how long the lock can hold, your program will crash after two seconds when the CLR notices that the finalizer thread is stuck. Moreover, this is just a mistake. You should never call Dispose () when another thread may still have an object reference.

Yes, implementing a finalizer without implementing IDisposable is not unheard of. Any shell of a COM object (RCW) does this. Also a Thread class. This was done because it is simply impractical to call Dispose (). In the case of a COM shell, because it is simply not possible to track all link counts. In the case of Thread, because of the need to Join () the thread so that you can call Dispose (), the target wins the thread.

Check out John Hannah's post. The implementation of your own finalizer is truly erroneous in 99.99% of cases. You have SafeHandle classes for transferring unmanaged resources. You need something rather obscure so as not to be wrapped by them.

+5
source share

The sample described above was the subject of eloquent work with overlapping issues of removal and finalization.

When we dispose, we want:

  • Dispose of all disposable member objects.
  • Dispose of the base object.
  • Free up unmanaged resources.

At the end we want:

  • Free up unmanaged resources.

This includes the following issues:

  • Disposal must be safe to call several times. Do not call x.Dispose();x.Dispose();
  • Finalization adds to the burden of garbage collection. If we avoid this, if we can, especially if we have already released unmanaged resources, we want to suppress the finalization, because it is no longer needed.
  • Access to completed facilities is fraught. If the object completes, then any finalisable members (which will also deal with the same problems as our class) may or may not already be completed and, of course, will be in the completion queue. Since these objects are likely to be managed by disposable objects, and since their removal will free up their unmanaged resources, we do not want to get rid of them in this case.

The code you specify will (after adding to the finalizer that calls Dispose(false) , manage these problems. In the case of a call to Dispose() it will clear both managed and unmanaged elements and suppress termination, as well as protect several calls (in in this case, it is not thread safe.) In the case of calling the finalizer, it clears the unmanaged elements.

However, this pattern is required only for the anti-pattern combining managed and unmanaged problems in one class. A much better approach is to process all unmanaged resources through a class that only applies to that resource, whether it be SafeHandle or a separate proprietary class. Then you will have one of two patterns, of which the latter will be rare:

 public class HasManagedMembers : IDisposable { /* more stuff here */ public void Dispose() { //if really necessary, block multiple calls by storing a boolean, but generally this won't be needed. someMember.Dispose(); /*etc.*/ } } 

This one does not have a finalizer and is not needed.

 public class HasUnmanagedResource : IDisposable { IntPtr _someRawHandle; /* real code using _someRawHandle*/ private void CleanUp() { /* code to clean up the handle */ } public void Dispose() { CleanUp(); GC.SuppressFinalize(this); } ~HasUnmanagedResource() { CleanUp(); } } 

This version, which will be much less common (not even performed on most projects), has the right to dispose exclusively using a single unmanaged resource for which the class is a wrapper and the finalizer does the same, t.

Since SafeHandle allows you to process the second template for you, you do not need it at all. In any case, the first example that I give will handle the vast majority of cases when you need to implement IDisposable . The template shown in your example should only be used for backward compatibility, for example, when you exit a class that uses it.

+3
source share

... you will notice that managed resources are not processed if recycling is false. How and when are they processed?

You did not include it in your sample, but often the type will have a destructor that will call Dispose(false) . Thus, when disposing is false , you “know” that you are in a finalizer call and therefore must * not * access any managed resources because they may have already been completed.

The GC finalization process ensures that finalizers are activated, and not the order in which they are called.

What does the call to GG.SuppressFinalize (this) do?

This prevents the GC from adding your object to the finalization queue and ultimately calling object.Finalize() (i.e. your destructor). This is performance optimization, nothing more.

As the pattern is written, it seems that they will be deleted (later) if you did not do anything in the "if (disposing)" section

May be; it depends on how this type is written. The crucial point for the IDisposable idiom is “deterministic finalization” - saying “I want your resources to be freed now” and what that means. If you “ignore” the disposing=true block and do not “forward” the Dispose() call, one of two disposing=true will happen:

  • If the type has a finalizer, the finalizer for the object can ultimately be called later.
  • If the type does not have a finalizer, the managed resource is leaked because Dispose() will never be called on them.

It’s important that you never acquire locks or use locks during your uncontrolled cleanup. Why is this? Does this apply to unmanaged resources?

This is a matter of sanity - YOUR sanity. The simpler your cleanup code, the better, and it is always a good idea not to throw exceptions from Dispose() . Using locks can lead to exceptions or deadlocks, which are a good way to wreck your day. :-)

does ever implement a finalizer (~ MyClass () in C #) without implementing an IDisposable

It is possible, but it will be considered a bad style.

+2
source share

The usual way for objects to be deleted is to call the Dispose() method. When this is done, calling SuppressFinalize removes the object from the finalizer queue, turning it into a regular managed object that can easily be garbage collected.

The finalizer is used only when the code cannot properly dispose of the object. The finalizer then calls Dispose(false) so that the object can at least try to clear unmanaged resources. Since any managed objects referenced by the objects may have already been garbage collected at this point, the object should not attempt to clear them.

+1
source share

Instead of trying to find out about the location using the template, you may need to roll over and try to find out why the template is implemented in this way based on CLR principles and the intended use of the IDisposable interface. There is a very good introduction to this, which should answer all your questions (and several that you did not think to ask) at http://msdn.microsoft.com/en-us/magazine/cc163392.aspx .

0
source share

If your class owns unmanaged resources directly, or if it can ever be inherited by a descendant class that does this, Microsoft will remove the template, which will provide a good way to link the finalizer and the removal tool. If there is no real possibility that either your class or its descendants will ever have unmanaged resources directly, you should remove the template code and simply implement Dispose directly. Given that Microsoft strongly recommended that unmanaged resources be wrapped in classes whose sole purpose is to store them (*) (and has classes such as SafeHandle for this purpose), there is really no need for template code.

(*) Garbage collection in .net is a multi-stage process; first, the system determines which objects are not referenced anywhere; then it makes a list of Finalize'able objects that are not mentioned anywhere. The list and all objects on it will be re-declared "live", which will mean that all the objects to which they refer will also live. At this point, the system will actually collect the garbage; he will then run all the finalizers on the list. If the object is held, for example. a direct link to the font resource (unmanaged), as well as links to ten other objects, which, in turn, contain a direct or indirect link to another hundred objects, and then the finalizer must get the object due to the unmanaged resource. When an object comes to collect, neither he nor 100+ objects to which he has a direct or indirect link will be entitled to collect until a pass after its finalizer is started.

If, instead of holding the direct descriptor of the font resource, the object contained a link to the object that contains the font resource (and nothing more), the last object needs a finalizer, but the first will not (since it does not contain a direct link to an unmanaged resource. Only one the object (the one that the finalizer was holding), and not 100+, had to survive in the first garbage collection.

0
source share

All Articles