2008-10-10 8 views
71

Czy istnieje metoda lub inny lekki sposób sprawdzenia, czy odniesienie dotyczy unieszkodliwionego obiektu?Jak można stwierdzić, czy odwołanie do obiektu IDisposable jest usuwane?

P.S. - To tylko ciekawość (śpij dobrze, nie w kodzie produkcyjnym). Tak, wiem, że mogę złapać ObjectDisposedException po próbie uzyskania dostępu do obiektu obiektu.

+10

Dunno. Wydaje się być ciekawym, że nie ma 'bool IsDisposed {get; } 'deklaracja w' System.IDisposable'. – nicodemus13

+2

@ nicodemus13: Metoda "Dispose" nakazuje obiektowi zwolnienie wszystkich zasobów, które uzyskał, ale jeszcze nie wydał. Jeśli obiekt nigdy nie posiada zasobów, jego metoda "Dispose" zazwyczaj nie będzie musiała nic robić; jeśli typ deklaruje 'void IDisposable.Dispose() {};' może w inny sposób zignorować 'IDisposable' bez narzutów dla instancji. Właściwość 'IsDisposed', która zgodnie z oczekiwaniami powinna stać się prawdziwa po wywołaniu' Dispose', wymagałaby dodania niepotrzebnej flagi Boolean do każdej instancji wielu typów, które w przeciwnym razie mogłyby zignorować 'Dispose'. – supercat

+0

Ale gdziekolwiek wywołasz metodę na obiekcie, który implementuje 'IDisposable', jak możesz sprawdzić, czy został najpierw usunięty? Zamiast zakładać, że tak nie jest i złapać wyjątek? Albo jakoś masz zarządzać życiem, abyś zawsze wiedział, czy jest zbędny, czy nie? – nicodemus13

Odpowiedz

-17

To zależy, istnieją IDisposable obiekty, które pozwalają wywołać metodę Dispose tyle, ile chcesz, i istnieje IDisposable obiekty, które rzucają ObjectDisposedException. W takim przypadku obiekty te muszą śledzić stan (zwykle implementowany z prywatnym polem boolowskim isDisposed).

+30

Nie jest to błędne: dokumentacja MSDN dla IDisposable.Dispose stwierdza, że ​​implementacje nie mogą zgłaszać wyjątku, jeśli Dispose jest wywoływana wiele razy. ObjectDisposedException może być generowany, gdy * inne * metody instancji są wywoływane po Dispose. – Joe

+5

Pozwól na wywołanie metody Dispose więcej niż raz bez rzucania wyjątku. Metoda powinna nic nie robić po pierwszym wywołaniu: http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx – Dandikas

+8

Dispose (a także finalizatory) powinny być wywoływane wiele razy bez wyrzucania wyjątku. ObjectDisposedExcpetions powinno wystąpić tylko wtedy, gdy spróbujesz użyć tego obiektu (uzyskaj dostęp do innych właściwości lub metod) po jego usunięciu. –

40

Nie - domyślna implementacja IDisposable wzór nie obsługuje on

35

System.Windows.Forms.Control ma właściwość IsDisposed który set to true after Dispose() is called. W swoich obiektach IDisposable można łatwo utworzyć podobną właściwość.

+0

OP chciał sprawdzić, czy istnieje podobna właściwość już na obiektach, których nie tworzy. Byłby to dobry pomysł na obiekty, które tworzymy, ale większość klas jednorazowych w .NET nie postępuje zgodnie z tą konwencją. Odpowiedź Dandikasa jest poprawna. – krillgar

+1

@krillgar, nie ma nic w pytaniu OP, które wspiera twoje stwierdzenie. –

9

Jeśli nie jest to twoja klasa i nie zapewnia własności IsDisposed (lub coś podobnego - nazwa jest tylko konwencją), to nie masz możliwości poznania.

Ale jeśli jest to twoja klasa i podążasz za canonical IDisposable implementation, to po prostu wystaw pole _disposed lub _isDisposed jako własność i sprawdź to.

16

Nie ma nic wbudowanego, co na to pozwoli. Będziesz musiał ujawnić właściwość boolean IsDisposed, która odzwierciedla wewnętrzną flagę.

public class SimpleCleanup : IDisposable 
{ 
    private bool disposed = false; 

    public bool IsDisposed 
    { 
     get 
     { 
      return disposed; 
     } 
    } 

    public SimpleCleanup() 
    { 
     this.handle = /*...*/; 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposed) 
     { 
      if (disposing) 
      { 
       // free only managed resources here 
      } 

      // free unmanaged resources here 
      disposed = true; 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 
} 
-1

Co chciałbym zrobić, to zadeklarować obiekty bez ich inicjowania, ale ustawić ich wartości domyślnych Nothing. Następnie, pod koniec pętli piszę:

If anObject IsNot Nothing Then anObject.Dispose() 

Powyżej znajduje się pełna próbka:

Public Sub Example() 
    Dim inputPdf As PdfReader = Nothing, inputDoc As Document = Nothing, outputWriter As PdfWriter = Nothing 

    'code goes here that may or may not end up using all three objects, 
    ' such as when I see that there aren't enough pages in the pdf once I open 
    ' the pdfreader and then abort by jumping to my cleanup routine using a goto .. 

GoodExit: 
    If inputPdf IsNot Nothing Then inputPdf.Dispose() 
    If inputDoc IsNot Nothing Then inputDoc.Dispose() 
    If outputWriter IsNot Nothing Then outputWriter.Dispose() 
End Sub 

To również działa świetnie na oddanie najważniejszych obiektów w szczycie rutyny, wykorzystując je do środka Try rutynowe i usuwania ich w Finally bloku:

Private Sub Test() 
    Dim aForm As System.Windows.Forms.Form = Nothing 
    Try 
     Dim sName As String = aForm.Name 'null ref should occur 
    Catch ex As Exception 
     'got null exception, no doubt 
    Finally 
     'proper disposal occurs, error or no error, initialized or not.. 
     If aForm IsNot Nothing Then aForm.Dispose() 
    End Try 
End Sub 
+6

@ LarsHöppner: Istotą tego pytania jest język-agnostyk, a dobrzy programiści C# powinni prawdopodobnie znać przynajmniej wystarczająco VB.NET, aby przeczytać powyższy kod (i programiści VB.NET powinni również nauczyć się wystarczająco dużo C#, aby odczytać kod C#, który nie robi ". t zrobić coś szczególnie egzotycznego). – supercat

+2

Dlaczego zrobiłbyś to wszystko zamiast używać instrukcji 'Using'? To istniało z pewnością w 2013 r., Kiedy ta odpowiedź została napisana. –

2

Sposób Dispose jest wymagany do wykonywania co oczyszczanie będzie Zapotrzebowanie przed usunięciem obiektu; jeśli nie jest wymagane żadne oczyszczanie, nie jest wymagane nic. Wymaganie, aby obiekt śledził, czy został usunięty, nawet jeśli metoda w innym przypadku nie zrobiłby nic, wymagałoby wielu obiektów o wartości IDisposable, aby dodać flagę z bardzo ograniczonymi korzyściami.

Mogło to być pomocne, jeśli IDisposable zawarte dwie właściwości - jeden, który wskazany czy obiekt potrzebne utylizacji, a jeden z co wskazywało, że obiekt nie był bezużyteczne przez dyspozycji. W przypadku obiektów, w których składowanie faktycznie coś robi, obie wartości będą początkowo prawdziwe i staną się fałszywe po Dispose. W przypadku obiektów, w których usuwanie nie wymaga żadnego czyszczenia, pierwsza metoda zawsze może zwracać fałsz, a druga zawsze jest prawdziwa, bez konieczności przechowywania flagi w dowolnym miejscu. Nie sądzę, że jest jakikolwiek sposób, aby te można było teraz dodać do .NET.

Powiązane problemy