IDisposable nesne referansının atılıp atılmadığı nasıl anlaşılır?


88

Bir referansın yerleştirilmiş bir nesneye olup olmadığını kontrol etmenin bir yöntemi veya başka bir hafif yolu var mı?

Not - Bu sadece bir meraktır (üretim kodunda değil, iyi uykular). Evet, ObjectDisposedExceptionnesnenin bir üyesine erişmeye çalışırken yakalayabileceğimi biliyorum .


11
Dunno. bool IsDisposed { get; }Üzerinde bir açıklama olmaması ilginç görünüyor System.IDisposable.
nicodemus13

3
@ nicodemus13: DisposeYöntem, bir nesneyi edindiği ancak henüz serbest bırakmadığı tüm kaynakları serbest bırakması için yönlendirir. Bir nesne hiçbir zaman kaynak tutmazsa, Disposeyönteminin genellikle hiçbir şey yapması gerekmez; tür bildirirse void IDisposable.Dispose() {};, IDisposableörnek başına ek yük olmadan yok sayabilir . IsDisposedHerhangi bir Disposeçağrının ardından gerçek olması beklenen bir özellik , aksi takdirde yok sayabilecek birçok türün her örneğine başka türlü gereksiz bir Boole bayrağı eklemeyi gerektirecektir Dispose.
supercat

1
Ancak, uygulayan bir nesnede bir yöntemi nerede çağırırsanız çağırın IDisposable, önce onun elden çıkarılıp atılmadığını nasıl kontrol edebilirsiniz? Olmadığını varsaymak ve bir istisna yakalamak yerine? Ya da bir şekilde yaşamınızı yönetmeniz mi gerekiyor, böylece onun elden çıkarılıp atılmadığını her zaman bilmelisiniz?
nicodemus13

3
@ nicodemus13: Bir nesneyi, herhangi bir bekleyen eylemi iptal etmek için bir sinyal olarak dış kod tarafından nesnenin elden çıkarılmasının bir sinyal olarak görmeye hazır olduğu durumlar haricinde, elden çıkarılmadığını ve elden çıkarılmayacağını bilmeden kullanmamalısınız. . Bir IsDisposedbayrak, kodun muhtemelen başarılı olamayacak işlemlerde zaman kaybetmesini önlemeye yardımcı olabilir, ancak yine de bir nesnenin IsDisposedkontrol ile onu kullanma girişimi arasında yer alması durumunda bir istisnayı ele almak gerekir.
supercat

WeakReferenceburada alakalı görünüyor. Bu tam olarak bir IDipose dedektörü değil, ancak GC'de olup olmadığını size söyler
Malachi

Yanıtlar:


49

Hayır - IDisposable modelinin varsayılan uygulaması onu desteklemiyor


42

System.Windows.Forms.Controlçağrıldıktan sonra trueIsDisposed olarak ayarlanmışDispose() bir özelliğe sahiptir . Kendi IDisposable nesnelerinizde, benzer bir özelliği kolayca oluşturabilirsiniz.


OP, yaratmadığı nesnelerde zaten benzer bir özellik olup olmadığını görmek istiyordu. Bu, oluşturduğumuz nesneler için iyi bir fikir olabilir, ancak .NET'teki çoğu tek kullanımlık sınıf bu kurala uymaz. Dandikas'ın cevabı doğru.
krillgar

2
@krillgar, OP'nin sorusunda iddianızı destekleyen hiçbir şey yok.
Ryan Lundy

19

Buna izin verecek yerleşik hiçbir şey yok. Dahili bir imha edilmiş bayrağı yansıtan bir IsDisposed boole özelliğini açığa çıkarmanız gerekir.

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);
    }
}

BTW, biri bu modeli kullanmaya başlarsa IDisposablePlus, miras alan IDisposableve içeren yeni bir arayüz ( veya her neyse) tanımlamaya yardımcı olur bool IsDisposed { get; }. Bu, IDisposablenesnelerinizden hangisinin desteklediğini bilmenizi kolaylaştırır IsDisposed.
ToolmakerSteve

C # 'ın çalışma biçimi nedeniyle bir arabirimi devralabileceğinizi sanmıyorum. Bir kolondan sonra bir arayüz yerleştirmek onu devralır. Arayüzü diğerine uygulamasını bekliyorum.
Moses

9

Bu sizin sınıfınız değilse ve bir IsDisposed özelliği sağlamıyorsa (veya benzer bir şey - isim sadece bir kuralsa), o zaman bilmenizin hiçbir yolu yoktur.

Ancak bu sizin sınıfınızsa ve kurallı IDisposable uygulamasını takip ediyorsanız, _disposed veya _isDisposed alanını bir özellik olarak gösterin ve kontrol edin.


2

DisposeYöntem, bir amacı terk edilmeden önce gerekli olacaktır her türlü temizlik gerçekleştirmek için gerekli olan; temizleme gerekmiyorsa, herhangi bir şey yapmaya gerek yoktur. Bir nesnenin atılıp atılmadığını takip etmesini istemek, Disposeyöntem başka türlü hiçbir şey yapmasa bile , birçokIDisposable çok sınırlı fayda için nesnenin bir bayrak eklemesini .

Biri IDisposablebir nesnenin atılması gerekip gerekmediğini ve biri nesnenin elden çıkarıldığında işe yaramaz hale getirilmediğini belirten iki özellik içermesi yararlı olabilirdi . Elden çıkarma işleminin gerçekten bir şey yaptığı nesneler için, her iki değer de başlangıçta doğru olur ve sonrasında yanlış olur Dispose. Elden çıkarma işleminin herhangi bir temizleme işlemi yapması gerekmeyen nesneler için, herhangi bir yerde bir bayrak saklamak zorunda kalmadan, ilk yöntem her zaman yanlış ve ikincisi her zaman doğru döndürebilir. Ancak bunların artık .NET'e eklenmesinin bir yolu olduğunu sanmıyorum.


IMHO, iki bayrak aşırıdır. Bir nesneye Dispose çağrıldığında tek bir bayrağın olduğu olağan paradigmaya bağlı kalmanın daha iyi olacağını düşünüyorum. Aksi takdirde, yalnızca Dispose çağrılmış olsa bile belirli nesnelerin "hala faydalı" olduğunu bilmek için karmaşıklık eklersiniz. O yoldan gitmeye değmez.
ToolmakerSteve

@ToolmakerSteve: Genellikle sıfır veya bir bayrak olacaktır. Elden çıkarılması gereken nesneler için, "elden çıkarma ihtiyaçları" ve "yararlıdır" özellikleri, atmadan önce "doğru / doğru" ve daha sonra "yanlış / yanlış" sonucunu verir, ancak elden çıkarmanın işlemsiz olacağı nesneler için her ikisi de koşulsuz olacaktır. "yanlış / doğru" döndür. Bir nesnenin, hiç olmadığı halde atılması gerektiğini ya da bir nesnenin her zaman olduğu zaman işe yaramadığını söylemek, oldukça iğrenç olurdu. Sanırım başka bir yaklaşım, bir türün bertaraf edilmesi gerekip gerekmediğini veya sadece umursamadığını belirtmek için numaralandırılmış bir tür kullanmak olacaktır.
supercat

@ToolmakerSteve: Bence IDisposablebir Disposedözelliğe sahip olmamanın en büyük sebebi , çağrının Disposeböyle bir özelliği ayarlamadığı true, ancak nesnelerin Disposeçağrılıp çağrılmadığının kaydını tutmasını gerektiren nesnelerin garip olarak algılanmasıdır. aksi takdirde ilgilenmek için hiçbir sebepleri olmayacak, önemli maliyet ve çok az fayda ekleyecektir.
supercat

1

Bunun eski olduğunu görüyorum ama bir cevap görmedim. DataSet gibi bazı tek kullanımlık nesnelerin ekleyebileceğiniz tek kullanımlık bir olayı yoktur.

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;
    }
}

Bunu bildiğim iyi oldu. DisposedOlay özellikle System.ComponentModel.IComponentarayüzün bir üyesidir .
ToolmakerSteve

-1

Yapmaktan hoşlandığım şey, nesneleri başlatmadan bildirmek, ancak varsayılan değerlerini olarak ayarlamaktır Nothing. Sonra döngünün sonunda şunu yazıyorum:

If anObject IsNot Nothing Then anObject.Dispose()

İşte tam bir örnek:

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

Bu aynı zamanda ana nesnelerinizi bir rutinin en üstüne koymak, onları bir Tryrutin içinde kullanmak ve ardından bir Finallyblok halinde atmak için harika çalışıyor :

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: Sorunun özü dilden bağımsızdır ve iyi C # geliştiricileri muhtemelen yukarıdaki kodu okuyacak kadar en azından yeterli VB.NET bilmelidir (ve VB.NET geliştiricileri de benzer şekilde C # kodunu okuyamayacak kadar C # öğrenmelidir. özellikle egzotik bir şey yapın).
supercat

3
Bir Usingifade kullanmak yerine tüm bunları neden yaptınız ? Bu, cevabın yazıldığı 2013 yılında kesinlikle vardı.
Cody Grey

Gerçekten "GoodExit:" GOTO için bu 1983 nedir? Lütfen onu kullanmayı bırak.
Musa

Bu soruya cevap vermiyor. Özellikle, bir kez inputPdfbir değere (Hiçbir Şey dışında) ayarlandığında, cevabınız inputPdfelden çıkarılıp atılmadığını bilmenin hiçbir yolunu göstermez . Bunu, attıktan sonra ayarlayarak kısmeninputPdf = Nothing çözebilirsiniz. Ancak bu , ile aynı nesneye işaret edilen diğer değişkenlere yardımcı olmaz inputPdf. : Yani bunu yaparsanız olduğunu inputPdf = New PdfReader, Dim pdf2 As PdfReader = inputPdf, inputPdf.Dispose, inputPdf = Nothing, hala o bilmenin bir yolu olacağını pdf2(Bu aynı nesnedir tanzim edilmiştir inputPdf).
ToolmakerSteve
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.