Finalize / Dispose pattern in C#

C# 2008

Pracuję nad tym już od jakiegoś czasu i nadal jestem zdezorientowany w niektórych kwestiach. Moje pytania są poniżej

  1. Wiem, że potrzebujesz tylko finalizera, jeśli pozbywasz się niezarządzanych zasobów. Jeśli jednak używasz zarządzanych zasobów, które wykonują połączenia z niezarządzanymi zasobami, czy nadal będziesz musiał wdrożyć finalizer?

  2. Jednakże, jeśli stworzysz klasę, która nie używa żadnych niezarządzanych zasobów, bezpośrednio lub pośrednio, czy możesz zaimplementować IDisposable, aby klienci twojej klasy mogli używać 'using statement'?

    Czy byłoby dopuszczalne zaimplementowanie IDisposable tylko po to, aby klienci twojej klasy mogli używać instrukcji using?

    using(myClass objClass = new myClass())
    {
        // Do stuff here
    }
    
  3. Opracowałem ten prosty kod poniżej, aby zademonstrować wzór Finalize/dispose:

    public class NoGateway : IDisposable
    {
        private WebClient wc = null;
    
        public NoGateway()
        {
            wc = new WebClient();
            wc.DownloadStringCompleted += wc_DownloadStringCompleted;
        }
    
    
        // Start the Async call to find if NoGateway is true or false
        public void NoGatewayStatus()
        {
            // Start the Async's download
                // Do other work here
            wc.DownloadStringAsync(new Uri(www.xxxx.xxx));
        }
    
        private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            // Do work here
        }
    
        // Dispose of the NoGateway object
        public void Dispose()
        {
            wc.DownloadStringCompleted -= wc_DownloadStringCompleted;
            wc.Dispose();
            GC.SuppressFinalize(this);
        }
    }
    

Pytanie o kod źródłowy:

  1. Tutaj nie dodałem finalizera, a normalnie finalizer będzie wywołane przez GC, a finalizator wywoła dyspozycję. Ponieważ nie mam finalizera, kiedy wywołać metodę Dispose? Czy to klient klasy musi to nazwać?

    Więc moja klasa w przykładzie nazywa się NoGateway i klient mógłby użyć i pozbyć się klasy w ten sposób:

    using(NoGateway objNoGateway = new NoGateway())
    {
        // Do stuff here   
    }
    

    Czy metoda Dispose zostanie wywołana automatycznie, gdy wykonanie osiągnie koniec używanego bloku, czy też klient musi ręcznie wywołać metodę dispose? tj.

    NoGateway objNoGateway = new NoGateway();
    // Do stuff with object
    objNoGateway.Dispose(); // finished with it
    
  2. Używam klasy webclient w mojej klasie NoGateway. Ponieważ webclient implementuje IDisposable interface, czy to oznacza, że WebClient pośrednio używa niezarządzanych zasobów? Czy istnieje trudna i szybka zasada do przestrzegania w tej sprawie? Skąd mam wiedzieć, że Klasa używa niezarządzanych zasobów?

Author: samis, 2009-05-22

13 answers

Zalecany wzorzec IDisposable to tutaj . Podczas programowania klasy, która używa IDisposable, generalnie powinieneś używać dwóch wzorców:

Implementując klasę zamkniętą, która nie używa niezarządzanych zasobów, po prostu implementujesz metodę Dispose, tak jak w normalnych implementacjach interfejsu:

public sealed class A : IDisposable
{
    public void Dispose()
    {
        // get rid of managed resources, call Dispose on member variables...
    }
}

Podczas implementacji klasy niepieczętowanej, zrób to tak:

public class B : IDisposable
{    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    }

    // only if you use unmanaged resources directly in B
    //~B()
    //{
    //    Dispose(false);
    //}
}

Zauważ, że nie zadeklarowałem finalizera w B; Powinieneś tylko zaimplementować finalizer, jeśli masz rzeczywiste niezarządzane zasoby do dyspozycji. CLR traktuje obiekty finalizowalne inaczej niż obiekty nie finalizowalne, nawet jeśli wywołane jest SuppressFinalize.

Więc nie powinieneś deklarować finalizera, chyba że musisz, ale dajesz dziedzicom swojej klasy hook, aby wywołali twój Dispose i zaimplementowali finalizer, jeśli używają bezpośrednio niezarządzanych zasobów: {]}

public class C : B
{
    private IntPtr m_Handle;

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }
        ReleaseHandle(m_Handle);

        base.Dispose(disposing);
    }

    ~C() {
        Dispose(false);
    }
}

Jeśli nie używasz zasobów niezarządzanych bezpośrednio (SafeHandle i przyjaciele się nie liczą, jak deklarują ich własne finalizery), a następnie nie implementuj finalizera, ponieważ GC radzi sobie z klasami finalizowalnymi inaczej, nawet jeśli później wyłączysz finalizer. Zauważ również, że nawet jeśli B nie ma finalizera, to nadal wywołuje SuppressFinalize, aby poprawnie radzić sobie z podklasami, które implementują finalizer.

Kiedy klasa implementuje IDisposable interface, oznacza to, że gdzieś są niezarządzane zasoby, których należy się pozbyć po zakończeniu używania klasy. Na rzeczywiste zasoby są hermetyzowane wewnątrz klas; nie musisz ich wyraźnie usuwać. Po prostu wywołanie Dispose() lub owinięcie klasy w {[10] } upewni się, że wszelkie niezarządzane zasoby zostaną usunięte w razie potrzeby.

 382
Author: thecoop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-29 12:52:40

Oficjalny wzór do wdrożenia IDisposable jest trudny do zrozumienia. Wierzę, że ten jest lepszy :

public class BetterDisposableClass : IDisposable {

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

  protected virtual void CleanUpManagedResources() { 
    // ...
  }
  protected virtual void CleanUpNativeResources() {
    // ...
  }

  ~BetterDisposableClass() {
    CleanUpNativeResources();
  }

}

An jeszcze lepszym rozwiązaniem jest zasada, że zawsze musisz utworzyć klasę wrapper dla dowolnego niezarządzanego zasobu, który musisz obsługiwać:

public class NativeDisposable : IDisposable {

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

  protected virtual void CleanUpNativeResource() {
    // ...
  }

  ~NativeDisposable() {
    CleanUpNativeResource();
  }

}

Z SafeHandle i jego pochodnych, klasy te powinny być bardzo rzadkie .

Wynik dla klas jednorazowych, które nie zajmują się bezpośrednio zasobami niezarządzanymi, nawet w obecności dziedziczenia, jest potężny: nie muszą już zajmować się niezarządzanymi zasobami. Będą proste do wdrożenia i zrozumienia:

public class ManagedDisposable : IDisposable {

  public virtual void Dispose() {
    // dispose of managed resources
  }

}
 110
Author: Jordão,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-29 15:52:26

Zauważ, że każda implementacja IDisposable powinna być zgodna z poniższym wzorcem (IMHO). Opracowałem ten wzór w oparciu o informacje z kilku doskonałych. NET "bogów" . NET Framework Design Guidelines (zauważ, że MSDN nie podąża za tym z jakiegoś powodu!). Wytyczne projektowe. NET Framework zostały napisane przez Krzysztofa Cwalinę (Architekt CLR w tym czasie) i Brada Abramsa (uważam, że CLR Program Manager w tym czasie) i Billa Wagnera ([efektywne C#] i [bardziej efektywne C#] (wystarczy wziąć Szukaj na Amazon.com:

Zauważ, że nigdy nie powinieneś implementować Finalizera, chyba że twoja klasa bezpośrednio Zawiera (nie dziedziczy) niezarządzane zasoby. Po zaimplementowaniu Finalizera w klasie, nawet jeśli nigdy nie zostanie wywołany, zagwarantowane jest życie dla dodatkowej kolekcji. Jest on automatycznie umieszczany w kolejce finalizacji (która działa na jednym wątku). I jeszcze jedna bardzo ważna uwaga...cały kod wykonywany w Finalizatorze (jeśli trzeba go zaimplementować) musi być bezpieczny dla wątku i wyjątek-Bezpieczny! Inaczej wydarzy się coś złego...(tj. nieokreślone zachowanie, a w przypadku wyjątku śmiertelna nieodwracalna awaria aplikacji).

Wzór, który ułożyłem (i napisałem fragment kodu), wygląda następująco:

#region IDisposable implementation

//TODO remember to make this class inherit from IDisposable -> $className$ : IDisposable

// Default initialization for a bool is 'false'
private bool IsDisposed { get; set; }

/// <summary>
/// Implementation of Dispose according to .NET Framework Design Guidelines.
/// </summary>
/// <remarks>Do not make this method virtual.
/// A derived class should not be able to override this method.
/// </remarks>
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.

    // Always use SuppressFinalize() in case a subclass
    // of this type implements a finalizer.
    GC.SuppressFinalize( this );
}

/// <summary>
/// Overloaded Implementation of Dispose.
/// </summary>
/// <param name="isDisposing"></param>
/// <remarks>
/// <para><list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
/// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.</item>
/// <item>If <paramref name="isDisposing"/> 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.</item></list></para>
/// </remarks>
protected virtual void Dispose( bool isDisposing )
{
    // TODO If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    try
    {
        if( !this.IsDisposed )
        {
            if( isDisposing )
            {
                // TODO Release all managed resources here

                $end$
            }

            // TODO Release all unmanaged resources here



            // TODO explicitly set root references to null to expressly tell the GarbageCollector
            // that the resources have been disposed of and its ok to release the memory allocated for them.


        }
    }
    finally
    {
        // explicitly call the base class Dispose implementation
        base.Dispose( isDisposing );

        this.IsDisposed = true;
    }
}

//TODO Uncomment this code if this class will contain members which are UNmanaged
// 
///// <summary>Finalizer for $className$</summary>
///// <remarks>This finalizer will run only if the Dispose method does not get called.
///// It gives your base class the opportunity to finalize.
///// DO NOT provide finalizers in types derived from this class.
///// All code executed within a Finalizer MUST be thread-safe!</remarks>
//  ~$className$()
//  {
//     Dispose( false );
//  }
#endregion IDisposable implementation

Oto kod do implementacji IDisposable w klasie pochodnej. Zauważ, że nie musisz jawnie wypisywać dziedziczenia z IDisposable w definicji klasy pochodnej.

public DerivedClass : BaseClass, IDisposable (remove the IDisposable because it is inherited from BaseClass)


protected override void Dispose( bool isDisposing )
{
    try
    {
        if ( !this.IsDisposed )
        {
            if ( isDisposing )
            {
                // Release all managed resources here

            }
        }
    }
    finally
    {
        // explicitly call the base class Dispose implementation
        base.Dispose( isDisposing );
    }
}

Zamieściłem tę implementację na moim blogu at: Jak prawidłowo wdrożyć wzór utylizacji

 33
Author: Dave Black,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-22 13:25:29

Zgadzam się z pm100 (i powinienem to wyraźnie powiedzieć we wcześniejszym poście).

Nigdy nie powinieneś implementować IDisposable w klasie, chyba że tego potrzebujesz. Aby być bardzo dokładnym, jest około 5 razy, kiedy kiedykolwiek potrzebujesz / powinieneś zaimplementować IDisposable:

  1. Twoja klasa jawnie zawiera (tzn. nie poprzez dziedziczenie) zarządzane zasoby, które implementują IDisposable i powinny zostać oczyszczone, gdy twoja klasa nie jest już używana. Na przykład, jeśli twoja klasa zawiera instancja strumienia, DbCommand, DataTable, itp.

  2. Twoja klasa jawnie zawiera wszelkie zarządzane zasoby, które implementują metodę Close () - np. IDataReader, IDbConnection, itp. Zauważ, że niektóre z tych klas implementują IDisposable przez posiadanie metody Disposable() oraz Close ().

  3. Twoja klasa jawnie zawiera niezarządzany zasób - np. obiekt COM, pointers (tak, możesz używać wskaźników w managed C#, ale muszą być zadeklarowane w blokach 'unsafe' , itd. W przypadku zasobów niezarządzanych, należy również upewnić się, aby zadzwonić System.Runtime.InteropServices.Szeryfie.ReleaseComObject() na RCW. Chociaż RCW jest, w teorii, zarządzanym opakowaniem, nadal pod okładkami trwa liczenie referencji.

  4. Jeśli twoja klasa subskrybuje wydarzenia za pomocą silnych odniesień. Musisz się wyrejestrować/odłączyć od wydarzeń. Zawsze, aby upewnić się, że nie są one null najpierw przed próbą wyrejestrowania/odłączenia oni!.

  5. Twoja klasa zawiera dowolną kombinację powyższych...

Zalecana alternatywa dla pracy z obiektami COM i konieczności korzystania z Marshala.ReleaseComObject() ma używać systemu.Runtime.InteropServices.Klasa bezpieczeństwa.

BCL (Base Class Library Team) ma dobry wpis na blogu o tym tutaj http://blogs.msdn.com/bclteam/archive/2005/03/16/396900.aspx

Jedną z bardzo ważnych uwag jest to, że jeśli pracujesz z WCF i sprzątanie zasobów, prawie zawsze należy unikać "używania" bloku. Istnieje wiele postów na blogach i kilka na MSDN o tym, dlaczego jest to zły pomysł. Pisałem też o tym tutaj - nie używaj 'using ()' z proxy WCF

 19
Author: Dave Black,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-21 16:13:51

Używanie lambda zamiast IDisposable.

Nigdy nie byłem zachwycony całym używaniem / IDisposable pomysłem. Problem polega na tym, że wymaga od rozmówcy:

  • wiedzą, że muszą używać IDisposable
  • pamiętaj, aby użyć 'using'.

Moim nowym preferowanym sposobem jest użycie metody fabrycznej i lambda zamiast

Wyobraź sobie, że chcę zrobić coś z SqlConnection(coś, co powinno być zawinięte w użycie). Klasycznie można by do

using (Var conn = Factory.MakeConnection())
{
     conn.Query(....);
}

New way

Factory.DoWithConnection((conn)=>
{
    conn.Query(...);
}

W pierwszym przypadku wywołujący nie mógł po prostu użyć składni using. W drugim przypadku Użytkownik nie ma wyboru. Nie ma metody, która utworzy obiekt SqlConnection, wywołujący musi wywołać DoWithConnection.

DoWithConnection wygląda tak

void DoWithConnection(Action<SqlConnection> action)
{
   using (var conn = MakeConnection())
   {
       action(conn);
   }
}

MakeConnection jest teraz prywatny

 11
Author: pm100,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-01 20:11:17

Nikt nie odpowiedział na pytanie, czy należy zaimplementować IDisposable, mimo że nie jest to potrzebne.

Krótka odpowiedź: Nie

Długa odpowiedź:

Pozwoli to konsumentowi z twojej klasy na użycie 'using'. Pytanie, które chciałbym zadać, brzmi - dlaczego mieliby to zrobić? Większość deweloperów nie będzie używać "używając", chyba że wiedzą, że muszą - i skąd wiedzą. Albo

  • its obviuos The them from experience (a socket class for example)
  • its udokumentowane
  • są ostrożni i widzą, że klasa implementuje IDisposable

Implementując IDisposable mówisz devs (przynajmniej niektórym), że ta klasa zawija coś, co musi zostać wydane. Będą używać 'using' - ale są inne przypadki, w których użycie nie jest możliwe (zakres obiektu nie jest lokalny); i będą musieli zacząć martwić się o żywotność obiektów w tych innych przypadkach-martwiłbym się na pewno. Ale to nie jest necessary

Zaimplementujesz Idisposable, aby umożliwić im używanie using, ale nie będą używać using, chyba że im tego każesz.

So dont do it

 9
Author: pm100,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-13 21:53:49
  1. Jeśli używasz innych zarządzanych obiektów, które używają niezarządzanych zasobów, nie jesteś odpowiedzialny za ich sfinalizowanie. Twoim obowiązkiem jest wywołanie Dispose na tych obiektach, gdy Dispose jest wywoływane na Twoim obiekcie i tam się kończy.

  2. Jeśli twoja klasa nie korzysta z ograniczonych zasobów, nie rozumiem, dlaczego chcesz, aby Twoja klasa zaimplementowała IDisposable. Powinieneś to robić tylko wtedy, gdy jesteś:

    • wiedz, że będziesz miał ograniczone zasoby w swoim obiekty wkrótce, ale nie teraz (I mam na myśli, że jak w "wciąż rozwijamy, to będzie tutaj, zanim skończymy", a nie jak w "myślę, że będziemy tego potrzebować")
    • wykorzystanie ograniczonych zasobów
  3. Tak, kod, który używa Twojego kodu, musi wywołać metodę usuwania Twojego obiektu. I tak, kod, który używa Twojego obiektu, może używać using tak, jak pokazałeś.

  4. (2 znowu?) Jest prawdopodobne, że WebClient używa albo niezarządzanych zasobów, albo innych zarządzanych zasobów, które implementują To możliwe. Dokładny powód nie jest jednak ważny. Ważne jest to, że implementuje IDisposable, a więc to na Ciebie spada działanie na tę wiedzę, pozbywając się obiektu, gdy skończysz z nim, nawet jeśli okaże się, że WebClient nie używa żadnych innych zasobów.

 4
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 16:55:34

@Icey,

Właściwie Twoja odpowiedź jest slighty Niepoprawna z 2 powodów:

Pierwszy,

using(NoGateway objNoGateway = new NoGateway())

Jest równoznaczne z:

try
{
    NoGateway = new NoGateway();
}
finally
{
    if(NoGateway != null)
    {
        NoGateway.Dispose();
    }
}

Może to zabrzmieć śmiesznie, ponieważ operator ' new 'nigdy nie powinien zwracać 'null', chyba że masz wyjątek OutOfMemory. Ale rozważ następujące przypadki: 1. Wywołujesz FactoryClass, który zwraca IDisposable resource lub 2. Jeśli masz typ, który może lub nie może dziedziczyć z IDisposable w zależności od jego implementacji-pamiętaj że widziałem wzór IDisposable zaimplementowany nieprawidłowo wiele razy na wielu klientach, gdzie programiści po prostu dodają metodę Disposable () bez dziedziczenia po IDisposable (bad, bad, bad). Możesz również mieć przypadek, że IDisposable Resources jest zwracany z właściwości lub metody (ponownie bad, bad, bad - don 't give away your IDisposable resources)

using(IDisposable objNoGateway = new NoGateway() as IDisposable)
{
    if (NoGateway != null)
    {
        ...

Jeśli operator ' as 'zwraca null (lub właściwość lub metodę zwracającą zasób), a kod w bloku 'using' chroni przeciwko 'null', Twój kod nie wybuchnie podczas próby wywołania Dispose na obiekcie null z powodu' wbudowanego ' sprawdzenia null.

Drugi powód, dla którego Twoja odpowiedź nie jest dokładna, wynika z następującego stmt:

Finalizer jest wywoływany przez GC niszcząc Twój obiekt

Po pierwsze, finalizacja (podobnie jak sama GC) jest niedeterministyczna. CLR określa, kiedy wywoła finalizator. czyli programista / kod nie ma pojęcia. Jeśli IDisposable wzorzec jest zaimplementowane poprawnie (jak wyżej napisałem) i GC.Wywołana została metoda SuppressFinalize (), Finalizer nie zostanie wywołany. Jest to jeden z głównych powodów, aby prawidłowo wdrożyć wzór poprawnie. Ponieważ na zarządzany proces przypada tylko 1 Wątek Finalizera, niezależnie od liczby procesorów logicznych, można łatwo obniżyć wydajność, tworząc kopię zapasową lub nawet zawieszając wątek Finalizera, zapominając o wywołaniu GC.SuppressFinalize ().

Zamieściłem poprawną implementację Wzór utylizacji na moim blogu: Jak prawidłowo wdrożyć wzór utylizacji

 4
Author: Dave Black,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-03 17:36:36

Wzór usunięcia:

public abstract class DisposableObject : IDisposable
{
    public bool Disposed { get; private set;}      

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

    ~DisposableObject()
    {
        Dispose(false);
    }

    private void Dispose(bool disposing)
    {
        if (!Disposed)
        {
            if (disposing)
            {
                DisposeManagedResources();
            }

            DisposeUnmanagedResources();
            Disposed = true;
        }
    }

    protected virtual void DisposeManagedResources() { }
    protected virtual void DisposeUnmanagedResources() { }
}

Przykład dziedziczenia:

public class A : DisposableObject
{
    public Component components_a { get; set; }
    private IntPtr handle_a;

    protected override void DisposeManagedResources()
    {
        try
        {
          Console.WriteLine("A_DisposeManagedResources");
          components_a.Dispose();
          components_a = null;
        }
        finally
        { 
          base.DisposeManagedResources();
        }
    }

    protected override void DisposeUnmanagedResources()
    {
        try
        {
          Console.WriteLine("A_DisposeUnmanagedResources");
          CloseHandle(handle_a);
          handle_a = IntPtr.Zero;
        }
        finally
        { 
          base.DisposeUnmanagedResources();
        }
    }
}

public class B : A
{
    public Component components_b { get; set; }
    private IntPtr handle_b;

    protected override void DisposeManagedResources()
    {
        try
        {
          Console.WriteLine("B_DisposeManagedResources");
          components_b.Dispose();
          components_b = null;
        }
        finally
        { 
          base.DisposeManagedResources();
        }
    }

    protected override void DisposeUnmanagedResources()
    {
        try
        {
          Console.WriteLine("B_DisposeUnmanagedResources");
          CloseHandle(handle_b);
          handle_b = IntPtr.Zero;
        }
        finally
        { 
          base.DisposeUnmanagedResources();
        }
    }
}
 3
Author: Andrei Krasutski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-28 11:46:03
using(NoGateway objNoGateway = new NoGateway())

Jest równoważne

try
{
    NoGateway = new NoGateway();
}

finally
{
    NoGateway.Dispose();
}

Finalizer jest wywoływany przez GC niszcząc Twój obiekt. Może to być w zupełnie innym czasie niż po opuszczeniu metody. Pozbywanie się IDisposable jest wywoływane natychmiast po opuszczeniu używającego bloku. Stąd wzorzec jest zwykle używany do uwolnienia zasobów natychmiast po tym, jak już ich nie potrzebujesz.

 2
Author: Daniel Fabian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 16:50:11

1) WebClient jest typem zarządzanym, więc nie potrzebujesz finalizera. Finalizer jest potrzebny w przypadku, gdy użytkownicy nie pozbywają się() twojej klasy NoGateway, a natywny typ (który nie jest zbierany przez GC) musi zostać później wyczyszczony. W takim przypadku, jeśli użytkownik nie wywoła Dispose (), zawarty WebClient zostanie usunięty przez GC zaraz po wykonaniu NoGateway.

2) pośrednio tak, ale nie powinieneś się o to martwić. Twój kod jest poprawny i nie możesz zapobiegaj łatwym zapomnieniom użytkowników o pozbyciu się ().

 2
Author: Jesse C. Slicer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 16:50:58

Wzór z msdn

public class BaseResource: IDisposable
{
   private IntPtr handle;
   private Component Components;
   private bool disposed = false;
   public BaseResource()
   {
   }
   public void Dispose()
   {
      Dispose(true);      
      GC.SuppressFinalize(this);
   }
   protected virtual void Dispose(bool disposing)
   {
      if(!this.disposed)
      {        
         if(disposing)
         {
            Components.Dispose();
         }         
         CloseHandle(handle);
         handle = IntPtr.Zero;
       }
      disposed = true;         
   }
   ~BaseResource()      
   {      Dispose(false);
   }
   public void DoSomething()
   {
      if(this.disposed)
      {
         throw new ObjectDisposedException();
      }
   }
}
public class MyResourceWrapper: BaseResource
{
   private ManagedResource addedManaged;
   private NativeResource addedNative;
   private bool disposed = false;
   public MyResourceWrapper()
   {
   }
   protected override void Dispose(bool disposing)
   {
      if(!this.disposed)
      {
         try
         {
            if(disposing)
            {             
               addedManaged.Dispose();         
            }
            CloseHandle(addedNative);
            this.disposed = true;
         }
         finally
         {
            base.Dispose(disposing);
         }
      }
   }
}
 1
Author: devnull,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-28 09:52:50

Z tego co wiem, zaleca się nie używać Finalizera / destruktora:

public ~MyClass() {
  //dont use this
}

Głównie dlatego, że nie wiadomo, kiedy i czy zostanie wywołany. Metoda usuwania jest znacznie lepsza, zwłaszcza jeśli używamy lub usuwamy bezpośrednio.

Używanie jest dobre. użyj go:)

 -4
Author: Nic Wise,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 16:56:53