Bagaimana seseorang mengetahui jika referensi objek IDisposable dibuang?

88

Adakah metode, atau cara ringan lainnya, untuk memeriksa apakah referensi ditujukan ke benda yang dibuang?

PS - Ini hanya keingintahuan (tidur nyenyak, bukan dalam kode produksi). Ya, saya tahu saya dapat menangkap ObjectDisposedExceptionsaat mencoba mengakses anggota objek.

Neil C. Obremski
sumber
11
Entahlah. Tampaknya aneh bahwa tidak ada bool IsDisposed { get; }deklarasi tentang System.IDisposable.
nicodemus13
3
@ nicodemus13: DisposeMetode ini mengarahkan objek untuk melepaskan setiap dan semua sumber daya yang telah diperolehnya tetapi belum dirilis. Jika sebuah objek tidak pernah memiliki sumber daya, Disposemetodenya umumnya tidak perlu melakukan apapun; jika tipe mendeklarasikannya, void IDisposable.Dispose() {};ia dapat mengabaikannya IDisposabletanpa overhead per instance. Sebuah IsDisposedproperti yang diharapkan menjadi benar mengikuti setiap Disposepanggilan akan memerlukan menambahkan bendera Boolean dinyatakan-tidak perlu untuk setiap contoh dari banyak jenis yang lain bisa mengabaikan Dispose.
supercat
1
Tapi, di mana pun Anda memanggil metode pada objek yang diimplementasikan IDisposable, bagaimana Anda bisa memeriksa apakah itu telah dibuang terlebih dahulu? Daripada berasumsi bahwa itu bukan dan menangkap pengecualian? Atau entah bagaimana Anda ditakdirkan untuk mengatur kehidupan sehingga Anda harus selalu tahu apakah itu dibuang atau tidak?
nicodemus13
3
@ nicodemus13: Seseorang umumnya tidak boleh menggunakan objek tanpa mengetahui bahwa itu belum dan tidak akan dibuang kecuali dalam kasus di mana seseorang siap untuk menganggap pembuangan objek oleh kode luar sebagai sinyal untuk membatalkan tindakan yang tertunda dengannya . Sebuah IsDisposedbendera dapat membantu mencegah kode dari membuang-buang waktu pada operasi yang tidak mungkin berhasil, tapi satu masih perlu untuk menangani pengecualian dalam kasus sebuah benda akan dibuang antara IsDisposedcek dan upaya untuk menggunakannya.
supercat
WeakReferencetampaknya relevan di sini. Ini sebenarnya bukan detektor IDipose, tetapi ini memberi tahu Anda apakah itu GC'd
Maleakhi

Jawaban:

49

Tidak - implementasi default dari pola IDisposable tidak mendukungnya

Dandikas
sumber
42

System.Windows.Forms.Controlmemiliki IsDisposedproperti yang disetel ke true setelah Dispose()dipanggil . Di objek IDisposable Anda sendiri, Anda dapat dengan mudah membuat properti serupa.

Ryan Lundy
sumber
OP sedang mencari untuk melihat apakah ada properti serupa yang sudah ada pada objek yang tidak dia buat. Ini akan menjadi ide bagus untuk objek yang kita buat, tetapi kebanyakan kelas sekali pakai di .NET tidak mengikuti konvensi ini. Jawaban Dandikas benar.
krillgar
2
@krillgar, tidak ada pertanyaan OP yang mendukung pernyataan Anda.
Ryan Lundy
19

Tidak ada bawaan yang memungkinkan hal ini. Anda perlu mengekspos properti boolean IsDisposed yang mencerminkan bendera pembuangan internal.

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);
    }
}
Scott Dorman
sumber
BTW, jika seseorang mulai menggunakan pola ini, ada baiknya untuk menentukan antarmuka baru ( IDisposablePlusatau apa pun) yang mewarisi IDisposabledan menyertakan bool IsDisposed { get; }. Ini memudahkan untuk mengetahui objek mana yang IDisposablemendukung IsDisposed.
ToolmakerSteve
Saya tidak berpikir Anda dapat mewarisi antarmuka karena cara kerja C #. Menempatkan antarmuka setelah titik dua mewarisinya. Saya berharap itu akan mengimplementasikan antarmuka di sisi lain.
Moses
9

Jika itu bukan kelas Anda dan tidak menyediakan properti IsDisposed (atau sesuatu yang serupa - namanya hanyalah konvensi), maka Anda tidak tahu.

Tetapi jika itu adalah kelas Anda dan Anda mengikuti implementasi IDisposable kanonik , maka cukup perlihatkan bidang _disposed atau _isDisposed sebagai properti dan periksa.

jop
sumber
2

The Disposemetode diperlukan untuk melakukan pembersihan apapun akan diperlukan sebelum sebuah benda ditinggalkan; jika tidak diperlukan pembersihan, Anda tidak perlu melakukan apa pun. Mewajibkan sebuah objek untuk melacak apakah telah dibuang, bahkan ketika Disposemetode tersebut tidak akan melakukan apa-apa, akan membutuhkan banyak halIDisposable objek untuk menambahkan tanda untuk manfaat yang sangat terbatas.

Mungkin akan membantu jika IDisposablemenyertakan dua properti - satu yang menunjukkan apakah suatu objek perlu dibuang , dan salah satunya menunjukkan bahwa objek tersebut tidak dianggap tidak berguna dengan pembuangan. Untuk objek di mana pembuangan benar-benar melakukan sesuatu, kedua nilai awalnya adalah benar, dan menjadi salah setelahnya Dispose. Untuk objek yang pembuangannya tidak perlu melakukan pembersihan apa pun, metode pertama selalu dapat mengembalikan false dan yang kedua selalu benar, tanpa harus menyimpan tanda di mana pun. Saya rasa tidak ada cara untuk menambahkannya ke .NET sekarang.

supercat
sumber
IMHO, dua bendera berlebihan. Saya pikir lebih baik untuk tetap menggunakan paradigma biasa, di mana seseorang memiliki satu bendera begitu Buang telah dipanggil pada sebuah objek. Jika tidak, Anda menambahkan kerumitan, hanya untuk mengetahui bahwa objek tertentu "masih berguna" meskipun Buang telah dipanggil. Tidak ada gunanya menempuh jalan itu.
ToolmakerSteve
@ToolmakerSteve: Biasanya akan ada nol atau satu bendera. Untuk objek yang memerlukan pembuangan, properti "perlu dibuang" dan "berguna" akan menghasilkan "benar / benar" sebelum dibuang dan "salah / salah" sesudahnya, tetapi untuk objek yang pembuangannya tidak ada operasi, keduanya akan tanpa syarat mengembalikan "false / true". Mengatakan bahwa suatu objek masih perlu dibuang ketika tidak pernah melakukannya, atau bahwa suatu objek tidak berguna ketika selalu ada, akan agak menjijikkan. Saya kira pendekatan lain akan menggunakan tipe enumerasi untuk menunjukkan apakah sebuah tipe perlu dibuang, telah dibuang, atau sama sekali tidak peduli.
supercat
@ToolmakerSteve: Saya pikir alasan utama IDisposabletidak memiliki Disposedproperti adalah karena akan dianggap aneh memiliki objek di mana pemanggilan Disposetidak akan menyetel properti seperti itu true, tetapi mengharuskan objek tersebut melacak apakah Disposedipanggil dalam kasus di mana jika tidak mereka tidak punya alasan untuk peduli akan menambah biaya yang signifikan dan sedikit manfaat.
supercat
1

Saya melihat ini sudah tua, tetapi saya tidak melihat jawabannya. Beberapa tidak semua objek sekali pakai seperti DataSet memiliki acara pembuangan yang dapat Anda lampirkan.

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;
    }
}
Musa
sumber
Senang mendengarnya. Secara khusus, Disposedacara adalah anggota System.ComponentModel.IComponentantarmuka.
ToolmakerSteve
-1

Yang ingin saya lakukan adalah mendeklarasikan objek tanpa menginisialisasi, tetapi menyetel nilai defaultnya ke Nothing. Kemudian, di akhir loop saya menulis:

If anObject IsNot Nothing Then anObject.Dispose()

Berikut contoh lengkapnya:

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

Ini juga berfungsi dengan baik untuk menempatkan objek utama Anda di bagian atas rutinitas, menggunakannya di dalam Tryrutinitas, dan kemudian membuangnya dalam satu Finallyblok:

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
JeffreyDurham
sumber
6
@ LarsHöppner: Inti dari pertanyaannya adalah bahasa-agnostik, dan pengembang C # yang baik mungkin harus tahu setidaknya cukup VB.NET untuk membaca kode di atas (dan pengembang VB.NET juga harus mempelajari cukup C # untuk membaca kode C # yang tidak melakukan sesuatu yang sangat eksotis).
supercat
3
Mengapa Anda melakukan semua ini daripada menggunakan Usingpernyataan? Itu pasti ada di tahun 2013 ketika jawaban ini ditulis.
Cody Gray
Sungguh "GoodExit:" apa ini 1983 untuk GOTO ?? Tolong hentikan penggunaan itu.
Musa
Ini tidak menjawab pertanyaan itu. Secara khusus, setelah inputPdfditetapkan ke nilai (selain Tidak Ada), jawaban Anda tidak menunjukkan cara untuk mengetahui apakah inputPdftelah dibuang. Anda dapat mengatasinya sebagian dengan mengatur inputPdf = Nothingsetelah membuang. Namun ini tidak akan membantu variabel lain yang telah diarahkan ke objek yang sama inputPdf. Itu jika Anda lakukan: inputPdf = New PdfReader, Dim pdf2 As PdfReader = inputPdf, inputPdf.Dispose, inputPdf = Nothing, ada masih akan ada cara untuk mengetahui bahwa pdf2dibuang (itu adalah objek yang sama seperti inputPdf).
ToolmakerSteve