Czy istnieje metoda lub inny lekki sposób sprawdzenia, czy odniesienie dotyczy usuniętego obiektu?
PS - To tylko ciekawostka (śpij dobrze, nie w kodzie produkcyjnym). Tak, wiem, że mogę złapać ObjectDisposedException
próbę uzyskania dostępu do członka obiektu.
c#
.net
dispose
idisposable
Neil C. Obremski
źródło
źródło
bool IsDisposed { get; }
deklaracji w sprawieSystem.IDisposable
.Dispose
Metoda nakazuje obiektowi zwolnienie wszelkich zasobów, które uzyskał, ale jeszcze nie zostały zwolnione. Jeśli obiekt nigdy nie przechowuje zasobów, jegoDispose
metoda na ogół nie będzie musiała nic robić; jeśli typ deklarujevoid IDisposable.Dispose() {};
, w przeciwnym razie może zignorowaćIDisposable
bez obciążenia na wystąpienie.IsDisposed
Nieruchomości, które spodziewano się stać prawdą następujące żadnegoDispose
połączenia wymagałoby dodanie inaczej-niepotrzebnego Boolean flagę każdym przypadku wielu rodzajów, które w przeciwnym razie mogłyby zignorowaćDispose
.IDisposable
, jak możesz sprawdzić, czy została usunięta jako pierwsza? Zamiast zakładać, że tak nie jest i łapać wyjątek? A może w jakiś sposób masz tak zarządzać swoim życiem, aby zawsze wiedzieć, czy jest on usuwany, czy nie?IsDisposed
Flaga może pomóc zapobiec kod z marnowania czasu na czynności, które nie mogą być może się uda, ale nadal będą musiały obsłużyć wyjątki w przypadku obiekt zostanie umieszczony pomiędzyIsDisposed
czeku i próbując je wykorzystać.WeakReference
wydaje się mieć tutaj znaczenie. To nie jest dokładnie wykrywacz IDipose'd, ale mówi ci, czy to GC'dOdpowiedzi:
Nie - domyślna implementacja wzorca IDisposable go nie obsługuje
źródło
System.Windows.Forms.Control
maIsDisposed
właściwość, która jest ustawiona na wartość true poDispose()
wywołaniu . W swoich własnych obiektach IDisposable możesz łatwo utworzyć podobną właściwość.źródło
Nie ma nic wbudowanego, co na to pozwoli. Konieczne byłoby ujawnienie właściwości logicznej IsDisposed, która odzwierciedla wewnętrzną usuniętą 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); } }
źródło
IDisposablePlus
lub cokolwiek innego), który dziedziczyIDisposable
i zawierabool IsDisposed { get; }
. Dzięki temu łatwo zorientujesz się, które z TwoichIDisposable
obiektów są obsługiwaneIsDisposed
.Jeśli to nie jest twoja klasa i nie zapewnia właściwości IsDisposed (lub czegoś podobnego - nazwa jest tylko konwencją), to nie masz możliwości dowiedzenia się.
Ale jeśli jest to Twoja klasa i postępujesz zgodnie z kanoniczną implementacją IDisposable , po prostu uwidocz pole _disposed lub _isDisposed jako właściwość i sprawdź to.
źródło
Ta
Dispose
metoda jest wymagana do wykonania dowolnego czyszczenia, które będzie wymagane, zanim obiekt zostanie porzucony; jeśli czyszczenie nie jest wymagane, nie trzeba nic robić. Wymaganie od obiektu śledzenia tego, czy został usunięty, nawet jeśliDispose
metoda w przeciwnym razie nic by nie zrobiła, wymagałoby od wieluIDisposable
obiektów dodania flagi z bardzo ograniczonymi korzyściami.Pomocne mogłoby być
IDisposable
uwzględnienie dwóch właściwości - jednej, która wskazywałaby, czy obiekt wymaga usunięcia , i jednej, która wskazywałaby, że przedmiot nie stał się bezużyteczny w wyniku usunięcia. W przypadku obiektów, w których usuwanie faktycznie coś robi, obie wartości będą początkowo prawdziwe, a później staną się fałszyweDispose
. W przypadku obiektów, w których usuwanie nie wymaga żadnego czyszczenia, pierwsza metoda może zawsze zwracać fałsz, a druga zawsze prawda, bez konieczności przechowywania flagi w dowolnym miejscu. Nie wydaje mi się jednak, aby można je było teraz dodać do .NET.źródło
IDisposable
brakuDisposed
właściwości jest to, że byłoby to postrzegane jako dziwne mieć obiekty, do których wywołanieDispose
nie ustawia takiej właściwościtrue
, ale wymagałoby, aby obiekty śledziły, czyDispose
zostało wywołane w przypadkach, gdy w przeciwnym razie nie mieliby powodu, aby się tym przejmować, spowodowałoby znaczne koszty i niewielkie korzyści.Widzę, że to jest stare, ale nie widziałem odpowiedzi. Niektóre nie wszystkie obiekty jednorazowego użytku, takie jak DataSet, mają usunięte zdarzenie, które można dołączyć.
class DisposeSample : IDisposable { DataSet myDataSet = new DataSet(); private bool _isDisposed; public DisposeSample() { // attach dispose event for myDataSet myDataSet.Disposed += MyDataSet_Disposed; } private void MyDataSet_Disposed(object sender, EventArgs e) { //Event triggers when myDataSet is disposed _isDisposed = true; // set private bool variable as true } public void Dispose() { if (!_isDisposed) // only dispose if has not been disposed; myDataSet?.Dispose(); // only dispose if myDataSet is not null; } }
źródło
Disposed
zdarzenie jest członkiemSystem.ComponentModel.IComponent
interfejsu.Lubię deklarować obiekty bez ich inicjowania, ale ustawiam ich domyślne wartości na
Nothing
. Następnie na końcu pętli piszę:If anObject IsNot Nothing Then anObject.Dispose()
Oto 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
Świetnie sprawdza się to również w przypadku umieszczania głównych obiektów na szczycie procedury, używania ich wewnątrz
Try
procedury, a następnie umieszczania ich wFinally
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
źródło
Using
instrukcji? To z pewnością istniało w 2013 roku, kiedy napisano tę odpowiedź.inputPdf
ustawieniu wartości (innej niż Nothing), Twoja odpowiedź nie pozwala stwierdzić, czyinputPdf
została usunięta. Możesz częściowo rozwiązać ten problem, ustawiającinputPdf = Nothing
po usunięciu. Jednak nie pomogłoby to żadnym innym zmiennym, które zostały wskazane na ten sam obiekt, coinputPdf
. To znaczy, jeśli nie:inputPdf = New PdfReader
,Dim pdf2 As PdfReader = inputPdf
,inputPdf.Dispose
,inputPdf = Nothing
, to nadal będzie w żaden sposób wiedzieć, żepdf2
jest umieszczony (jest to ten sam obiekt, jakinputPdf
).