IDisposable czy metoda Dispose() jest wywoływana automatycznie?

0

Mam artykuł o IDisposable: http://msdn.microsoft.com/pl-pl/library/system.idisposable.aspx
i tam jest taki kod:

 
using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
{
    // A base class that implements IDisposable.
    // By implementing IDisposable, you are announcing that
    // instances of this type allocate scarce resources.
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource.
        private IntPtr handle;
        // Other managed resource this class uses.
        private Component component = new Component();
        // Track whether Dispose has been called.
        private bool disposed = false;

        // The class constructor.
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;

            }
        }

        // Use interop to call the method necessary
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code.
        // This destructor will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create
        // and use the MyResource object.
    }
}

W destruktorze jest komentarz, że wywołanie Dispose(false) jest opcjonalne. Czyli, że mogę usunąć destruktor a metoda Dispose() zostanie wywołana sama automatycznie?? Bo na tej stronie z kolei w klasie StudentRepository: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application jest podobny przykład i tam nie ma destruktora wywołującego metodę Dispose() czyli sama się chyba wywołuje?

1

Dispose() jest wywoływane przy niszczeniu obiektu przez GC. To oznacza, że masz zagwarantowane, że metoda zostanie wywołana, ale nie wiadomo kiedy.
Jaki jest sens implementowania IDisposable, kiedy i tak GC po Tobie posprząta? Taki, że Twój obiekt może zawierać uchwyty do niezarządzanych obiektów systemu (pliki, gniazda, ...), może blokować dużą ilość pamięci czy innych zasobów. Owszem, możesz to wszystko posprzątać w destruktorze, jednak MS zaleca robienie takich rzeczy w Dispose(). (http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx#sectionToggle1). Dlaczego Dispose() jest takie ważne? Bo pozwala na korzystanie z using, które to gwarantuje wywołanie metody Dispose() niezależnie od tego, czy wykonywany kod zadziała, czy też poleci wyjątek, a to z kolei gwarantuje posprzątanie po obiekcie i - tu najważniejsza część - nie w dowolnym momencie (gdy GC zacznie odśmiecanie), ale w chwili opuszczania klauzuli using.
Wiem, że nie do końca odpowiadam na Twoje pytanie, więc może na koniec słówko w temacie: [tu był edit po komentarzu anakondy] ani Dispose(), ani Dispose(bool) nie zostaną wywołane przez GC (dziwne). Zresztą zerknij na http://stackoverflow.com/questions/5225168/dispose-vs-disposebool - overload z parametrem to tylko "best-practices" zalecane przez MS.
Edit: wklejone przez Ciebie Dispose(bool) jest źle napisane - jest tread-unsafe. Brakuje lock i dodatkowego sprawdzania warunk (tak jak to się robi przy thread-safe singleton).

0

W przykladzie ze StudentRepository Dispose jest wywolywany tylko, ze przez klase, ktora z niego korzysta (StudentController):

protected override void Dispose(bool disposing)
{
    studentRepository.Dispose();
    base.Dispose(disposing);
} 
0

A na tej stronie jest napisane, że Dispose() nie jest automatycznie wywoływana:
http://stackoverflow.com/questions/1691846/does-garbage-collector-call-dispose

"The GC does not call Dispose, it calls your finalizer (which you should make call Dispose(false))."

Czyli w destruktorze trzeba wywoływać Dispose() jednak. Tylko po co w takim razie na msdn dali komentarz, że jest to opcjonalne.

1 użytkowników online, w tym zalogowanych: 0, gości: 1