Sorry, I asked a similar question earlier and there were answers to it. But again I ran into this topic and it blows my head off. So, John Sharp's book, Microsoft Visual C # Step by Step 9ed. Part 2, chapter 14.
Quote:
class Example : IDisposable
{
private Resource scarce; // scarce resource to manage and dispose
private bool disposed = false; // flag to indicate whether the resource
// has already been disposed
~Example()
{
this.Dispose(false);
}
public virtual void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// release large, managed resource here
}
// release unmanaged resources here
this.disposed = true;
}
}
public void SomeBehavior() // example method
{
checkIfDisposed();
}
private void checkIfDisposed()
{
if (this.disposed)
{
throw new ObjectDisposedException('Example: object has been disposed');
}
}
}
Notice the following features of the Example class:
The class implements the IDisposable interface.
The public Dispose method can be called at any time by your application code.
The public Dispose method calls the protected and overloaded version of the Dispose method that takes a Boolean parameter, passing the value true as the argument. This method actually performs the resource disposal.
The destructor calls the protected and overloaded version of the Dispose method that takes a Boolean parameter, passing the value false as the argument. The destructor is called only by the garbage collector when your object is being finalized.
You can call the protected Dispose method safely multiple times. The variable disposed indicates whether the method has already been run and is a safety feature to prevent the method from attempting to dispose of the resources multiple times if it is called concurrently. (Your application might call Dispose, but before the method completes, your object might be subject to garbage collection and the Dispose method run again by the CLR from the destructor.) The resources are released only the first time the method runs.
The protected Dispose method supports disposal of managed resources (such as a large array) and unmanaged resources (such as a file handle). If the disposing parameter is true, this method must have been called from the public Dispose method. In this case, the managed resources and unmanaged resources are all released. If the disposing parameter is false, this method must have been called from the destructor, and the garbage collector is finalizing the object. In this case, it is not necessary (or exception-safe) to release the managed resources because they will be, or might already have been, handled by the garbage collector, so only the unmanaged resources are released.
The public Dispose method calls the static GC.SuppressFinalize method. This method stops the garbage collector from calling the destructor on this object because the object has already been finalized.
All the regular methods of the class (such as SomeBehavior) check to see whether the object has already been discarded. If it has, they throw an exception.
I have highlighted in bold a paragraph in which I cannot understand under what circumstances this is possible. In particular this:
Your application might call Dispose, but before the method completes, your object might be subject to garbage collection and the Dispose method run again by the CLR from the destructor.
I do not understand. If the Dispose method has not yet completed, then the operation this.disposed = true has not yet been performed, then this.disposed is still false. The object will be garbage collected while this.Dispose (true) is running. I have already come to terms with this - the method is still working, in the still working method there are operations using the this keyword, that is, we are still working with this object, there are operations using the members of this object (this.disposed = true), and when the method ( this.Dispose (true)) completes, after it the GC.SuppressFinalize (this) code should work, which also contains the this keyword, but still, for some reason our object is subject to garbage collection as written in the book.
Good. Let's assume.
But this.disposed is still false, and when garbage collected and the this.Dispose (false) method is called from the destructor, the this.disposed field won't play any role.
Was the author wrong? Why does he write about the role of the disposed field and give an example in which this field is useless? Or am I losing my mind?