📜 ⬆️ ⬇️

About poor Dispose put in a word

A little about the release of resources in .Net.

warning: the text below is just a retelling in your own words of long-known information that is available online in Russian and English .

What to do when I want to release unmanaged resources in .Net? You can put the resource release code in the finally section and this will be the easiest way. Not very elegant, but it is guaranteed to work without any pitfalls:
DBConnection conn = new DBConnection();
try
{
conn.Open();
//...
}
finally
{
conn.Close();
}


* This source code was highlighted with Source Code Highlighter .

Let's complicate the task. We wrote a library class that works with unmanaged resources. According to the law of meanness (or large numbers - as you prefer), besides the guru, there will also be govnodery. That will calmly forget to call the method to release unmanaged resources. And then they will spit on the library that is crookedly written by YOU .
')
So you want to write your class so that the method that frees up resources (no longer important - they are managed or unmanaged) is automatically called by the garbage collector if the user forgot to call it himself.

To release unmanaged resources, it is proposed to use the IDisposable interface with a single Dispose function, which should release resources. And the main task here is not to write this function, but to write the code so that this function is called necessarily.

We have two cases:
1) The user invoked the method to free the resources itself.
2) The user did not ask for the release of resources and the GC should do this

The first option looks like this:
using (MyClass x = new MyClass())
{
x.SomeMethod();
//...
}


* This source code was highlighted with Source Code Highlighter .

or so:
MyClass x;
try
{
x = new MyClass();
x.SomeMethod();
//...
}
finally
{
if (x != null )
x.Dispose();
}

* This source code was highlighted with Source Code Highlighter .

The second option looks like this:
MyClass x = new MyClass();
x.SomeMethod();
//...


* This source code was highlighted with Source Code Highlighter .

Let's think about how to implement the MyClass class itself and its Dispose method so that in all these cases our code works? We list the requirements that lie on the surface:
1) Dispose method should not fall if it is called several times in a row (protection against a fool)
2) the Dispose method should not be called from the GC if it was called explicitly (and, accordingly, should be called from the GC if the user did not call it himself).

It is from these two considerations that the disposed variable appeared in the proposed implementation of the MyClass class (to be able to distinguish the already freed class from the non-freed class), the destructor (to call the Dispose method from GC) and, finally, the wrapper over the Dispose function - the function with the bool parameter Dispose ( bool manual) (to distinguish manual calling Dispose from automatic). Oh yes. And it is necessary to distinguish a manual call from an automatic one in order by using the GC.SuppressFinalize method (this); disable the destructor call.

Total we get this class (simple copy-paste from msdn):
public class MyResource: IDisposable
{
private bool disposed = false ;

// IDisposable
//
//
public void Dispose()
{
Dispose( true ); //
GC.SuppressFinalize( this ); // , GC
}

//
~MyClass()
{
Dispose( false ); // GC
}

//
private void Dispose( bool manual)
{
if (! this .disposed)
{
if (manual)
{
// managed
//...

// - Dispose
// managed -
// Dispose,
// Dispose GC
}

// unmanaged
//...

disposed = true ;
}
}
}


* This source code was highlighted with Source Code Highlighter .

That's all. There is still a slight complication of this code if you inherit from the class MyClass (there you want to provide a call to the Dispose method from the parent class by overriding the Dispose method (bool)). But this is not so difficult.

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


All Articles