For Microsoft built classes that inherit IDisposable, should I explicitly call Dispose?

As for the Microsoft built-in classes that inherit from IDisposable, should I explicitly call Dispose to prevent memory leaks?

I understand that it is best to use Dispose (or it is better to use a use block), however when programming, I usually don’t always immediately understand that a class inherits from IDisposable.

I also understand that the implementation of IDisposable at Microsoft is a bit frustrated, so they created an article explaining the correct use of IDisposable .

In short, in what cases can you forget to call Dispose?

+4
source share
7 answers

It depends on two things:

  • What happens in the Dispose method
  • Is the finalizer called Dispose

Dispose functionlity
Dispose can perform several types of actions, for example, close a resource descriptor (for example, a file stream), change the state of a class, and release other components used by the class itself.
If a resource is released (for example, a file), there is a difference in functionality between calling it explicitly and waiting for it to be called during garbage collection (provided that the finalizer calls are selected).
If there are no state changes and only components are released, there will be no memory leak since the object will later be freed by the GC.

Finalizer
In most cases, one-time types call the Dispose method from the finalizer. If this is the case, and assuming that the context in which dispose is called does not matter, then there is a high probability that you will not notice the difference if the object is not deleted explicitly. But if Dispose is not called from the finalizer, then your code will behave differently.

Bottom line - in most cases, it’s better to delete the object explicitly when you are done with it.

A simple example of where it is better to call Dispose explicitly: suppose you use FileStream to write some content and include no, the file is blocked by the process until the GC receives the object. The file may also not clear all the content to the file, so if the process fires at some point after the recording is complete, it does not guarantee that it will actually be saved.

+4
source

There are several questions in the main question

Do I explicitly need to call Dispose to prevent a memory leak?

Calling Dispose on anyone that implements IDisposable is highly recommended and can even be a fundamental part of the types contract. There is almost no reason not to call Dispose when you are done with the object. The IDisposable is for placement.

But would a Dispose call create a memory leak? Maybe. It very much depends on what exactly this object does Dispose in it. Many free memories, some indentation from events, other free pens, etc. This may not be a memory leak, but it will almost certainly have a negative effect on your program.

When can I forget to call Dispose?

I would start from scratch. The vast majority of objects there are IDisposable carry no good reason. Failure to call Dispose damage your program.

+10
source

It may be safe to not cause Dispose , but the problem is to know when it is.

Good 95% of IEnumerator<T> implementations have Dispose , which can be ignored, but 5% is not only 5%, which will lead to an error, but 5%, which will lead to disgusting tracing of the error. Moreover, the code that receives the passed IEnumerator<T> will see both 95% and 5% and will not be able to dynamically separate them (it is possible to implement a non-generic IEnumerable without implementing IDisposable , and how well it turned out, we can assume that MS decided to make IEnumerator<T> inherit from IDisposable !).

Of the rest, maybe 3 or 4% of the time, when it is safe. Presently. You do not know that 3% does not look at the code, and even then the contract says that you should call it, so the developer can depend on you if they release a new version, where it is important.

Thus, it always calls Dispose() . (I can think of an exception, but it is frankly too strange, even going into details, and in this case it’s still safe to call it, and not vital).

On the issue of implementing IDisposable avoid the template in the damn document yourself.

I view this pattern as an anti-pattern. This is a good template for implementing both IDisposable.Dispose and the finalizer in a class that contains both managed and unmanaged resources. However, storing both managed IDisposable and unmanaged resources is, firstly, a bad idea.

Instead

If you have an unmanaged resource, then you do not have unmanaged resources that implement IDisposable . Now the Dispose(true) and Dispose(false) code codes are the same, so they really can become:

 public class HasUnmanaged : IDisposable { IntPtr unmanagedGoo; private void CleanUp() { if(unmanagedGoo != IntPtr.Zero) { SomeReleasingMethod(unmanagedGoo); unmanagedGoo = IntPtr.Zero; } } public void Dispose() { CleanUp(); GC.SuppressFinalize(this); } ~HasUnmanaged() { CleanUp(); } } 

If you manage the resources that need to be disposed of, just do this:

 public class HasUnmanaged : IDisposable { IDisposable managedGoo; public void Dispose() { if(managedGoo != null) managedGoo.Dispose(); } } 

There is no critical “disposing" bool (how can you call Dispose something and take false for something called disposing ?). Do not worry about finalizers for 99.99% of the time when you do not need them (the second sample is more common than the first). Things are good.

Do you really need something that has both a managed and unmanaged resource? No, in fact, you do not transfer an unmanaged resource to your own class, which works as a descriptor, and then this descriptor matches the first template above, and the main class is suitable for the second.

Use only the CA10634 pattern when you are forced because you inherited from the class that did this. Fortunately, most people no longer create new ones like that.

+3
source

Never forget to call Dispose (or, as you say, it's better to use using ).

I think if the goal of your program is to cause unmanaged resource leaks. Then, perhaps, everything will be fine.

+1
source

The implementation of IDisposable means that the class uses unmanaged resources. You should always call Dispose() (or use the using block when possible) when you are sure you are done with the class. Otherwise, you do not need to allocate unmanaged resources.

In other words, never forget to call Dispose() .

0
source

Yes, always call dispose. Either explicitly or implicitly (using). Take, for example, the Timer class. Unless you explicitly stop the timer and destroy it, it will continue to fire until the garbage collector begins to collect it. This can lead to crashes or unexpected behavior.

It is always best to make sure that Dispose is invoked as soon as you are done with it.

0
source

Microsoft (perhaps not officially) says it’s normal not to invoke Dispose in some cases.

Microsoft's Stephen Tub writes (about calling Dispose on Task):

In short, as is usually the case in .NET, aggressively dispose of if it is easy and correct to do based on the structure of your code. If you start making strange turns to Dispose (or in the case of tasks, use additional synchronization to ensure that it is safe for recycling, since Dispose can only be used after the task is completed), it is best to rely on completion to take care of things. In the end, it's best to measure, measure, measure, to see if you really have a problem before you go out of your way to make the code smaller in order to implement the cleanup functions.

[bold emphasize mine]

Another case is the underlying threads

 var inner = new FileStrem(...); var outer = new StreamReader(inner, Encoding.GetEncoding(1252)); ... outer.Dispose(); inner.Dispose(); -- this will trigger a FxCop performance warning about calling Dispose twice. 

(I disabled this rule)

0
source

Source: https://habr.com/ru/post/1390676/


All Articles