0

Is it right that in C# Destructor (Finalizer) you can not access managed members of your class? If it is true, why is it? What other C# finalizer restrictions you know?

Example:

class MyClass
{
    private FileStream _fs;
    private IntPtr _handle;

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

    ~MyClass()
    {
        Dispose(false);
    }

    private void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            _fs.Dispose(); // Won't be accessed from destructor
        }

        //some way to release '_handle' - this happans anyway (Called by Dispose or by Destructor)
    }
}
shA.t
  • 16,580
  • 5
  • 54
  • 111
AlonP
  • 903
  • 1
  • 9
  • 16
  • Destructors are called not only when instance gets garbage collected but also when the program exits. If you try to access some managed members of your class, you could face the issue that some of them already had their destructors called. – JustSomeGuy Mar 12 '15 at 14:35
  • Just in case you weren't aware, finalizers are considered bad practice in c# (along with many other memory management operations that subvert the built in garbage collection). See the IDisposable pattern as an alternative (https://msdn.microsoft.com/en-us/library/system.idisposable%28v=vs.110%29.aspx) – Kaido Mar 12 '15 at 14:36

3 Answers3

1

You can .But whats the point ? the object you are in has become unreachable so all those managed resources are already being collected by GC.So calling dispose on them is unnecessary.

from msdn

Using Destructors to Release Resources: In general, C# does not require as much memory management as is needed when you develop with a language that does not target a runtime with garbage collection. This is because the .NET Framework garbage collector implicitly manages the allocation and release of memory for your objects. However, when your application encapsulates unmanaged resources such as windows, files, and network connections, you should use destructors to free those resources. When the object is eligible for destruction, the garbage collector runs the Finalize method of the object.

Explicit Release of Resources If your application is using an expensive external resource, we also recommend that you provide a way to explicitly release the resource before the garbage collector frees the object. You do this by implementing a Dispose method from the IDisposable interface that performs the necessary cleanup for the object. This can considerably improve the performance of the application. Even with this explicit control over resources, the destructor becomes a safeguard to clean up resources if the call to the Dispose method failed.

https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

Rohit
  • 10,056
  • 7
  • 50
  • 82
1

Yes, you shouldn't access other managed classes from the finalizer, or from Dispose when that method is called by the finalizer. By the time an object's finalizer is executed, the state of any managed object it once referenced is indeterminate. They may still exist, may be awaiting finalization themselves, or may have already been garbage-collected. In addition, finalizers are run on a different thread.

Chris Mantle
  • 6,595
  • 3
  • 34
  • 48
1

This is a .NET 1.x implementation detail that has been incredibly difficult to get rid of. Part of the problem must be that the majority of books about .NET were written before 2005, they all have a chapter about finalizers and they all have it dead wrong.

Roughly, if you think you need a finalizer then you're wrong 99.9% of the time. That finalizable resource needs to be wrapped in its own class and that class needs to have a finalizer. If you think you need to implement the Disposable pattern then you're wrong ~95% of the time. Definitely wrong here. But sometimes you don't have a choice if your base class already made the mistake of implementing it. Several of the .NET Framework classes have this mistake, a problem that Microsoft couldn't fix anymore.

The that class with the finalizer in the previous chapter is not one you should implement yourself. It was already written, .NET 2.0 acquired the SafeHandle classes. You, at best, might need to derive your own class if the Release() method isn't one that's already provided in the framework. SafeBuffer is useful for pointer-based resources.

The big, big difference is that these classes are pretty special, they have critical finalizers. Which is an expensive word that means that they are guaranteed to run, even if the finalizer thread bombed on an unhandled exception. Not actually that important in the majority of the LOB apps, if they go down in flames then the OS cleanup is usually good enough. But essential when .NET code runs in a host that has a long uptime guarantee. SQL Server is a good example, having to reboot it because too much SQL/CLR code bombed and leaked handles is bad for business.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Why am i wrong in this case? i have a member (filestream) that is disposable so i need to assure that his dispose is being called. – AlonP Mar 12 '15 at 15:47
  • So just call its Dispose() method in your Dispose() method. That's all you need, nothing to do with finalization. – Hans Passant Mar 13 '15 at 19:07