2009-07-28 8 views
5

Sınıfım, Interop'tan bir nesne içeriyor ve üzerine bir şeylerin atanmasına neden olan bir yöntem çağırıyor. Aynı zamanda bu maddeleri boşaltmak için bir yöntem sunar, bu yüzden ben Dispose() bu çağırmalıdır bekliyoruz:Bir Interop COM Nesnesi sarılırken atma desenini C# olarak nasıl uygularım?

class MyClass : IDisposable 
{ 
    private DllName.ComClassName comInstance; 

    void SomeMethod() 
    { 
     comInstance = new DllName.ComClassName(); 
     comInstance.AllocStuff(); 
    } 

    public void Dispose() 
    { 
     comInstance.FreeThatStuff(); 
    } 
} 

Şimdi, imha deseni takip etmek bütün bu genişletmek gerekir. Ben (Interop'un ne değildir içine yönetilen yönetilmeyen sarar?) Öylesine comInstance yönetilmektedir varsayarak, serbest bırakmak için başka tek kullanımlık ya da yönetilmeyen kaynaklara sahip, ben desen çözer düşünüyorum: I sürece sızdırıyor

public void Dispose() 
{ 
    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 
} 

Dispose desenini kusurlu yapacak olan MyClass örneklerinde Dispose() öğesini açıkça arayın. Böylece comInstance yönetilmeyen olmalıdır demek ve desen için çözer kapsamaz:

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

~MyClass() 
{ 
    DisposeComInstance(); 
} 

private void DisposeComInstance() 
{ 
    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 
} 

EDIT:

  1. Sadece benim sınıf mühür olabilir, tam desenli benim sınıf yığılan önlemek için?
  2. ComClassName (ve genel olarak herhangi bir sınıfta) yönetilmediğini nasıl anlarım?

cevap

2

Neredeyse çivilenmiş gibi görünüyor. Yönetilen öğelerin atılması gerektiğine işaret eden bir boolean parametresi alan korunan sanal bir Disposing'in bulunduğu desene geri dönersiniz. Bu şekilde birisinin arkanızdan gelmesi implement IDisposable properly'a devam edecektir. Ben yedek olarak bir finalizer sahip önermek olanlar katılıyorum, neden, Öncelikle Implementing IDisposable and the Dispose pattern properly.

+1

Meta-comment: Dispose (bool) öğesinin defalarca defalarca çağrılmaya tahammül edebileceğinden emin olun. Ayrıca, bir istisna olasılığını en aza indirmeye çalışın (her zaman mümkün değil). – user7116

+1

Meta-meta yorumu - bunun yanı sıra, yönetilmeyen temizlemeniz sırasında kilitleri veya kilitleri kullanmamanız önemlidir. – womp

3

Sonuçta bu desen tür istiyorum , ama açıkça myClass.Dispose veya 'using' aracılığıyla çağırarak çağrılmasından kaçınmaya çalışın.

örn.

var myClass = new MyClass() 
try 
{ 
    //do stuff 
} 
finally 
{ 
    myClass.Dispose(); 
} 

veya

using (var myClass = new MyClass()) 
{ 
    //do stuff 
} 

Marshall.ReleaseComObject

COM nesnelerinin bir sürü kullanıyorsanız, ben de açıkça başvurular temizlemeye Mashall.ReleaseComObject (comObj) kullanmanızı öneriyoruz RCW.

Yani, böyle kod başka bir yerde önerdi:

if (comInstance != null) 
{ 
    comInstance.FreeStuff(); 
    comInstance = null; 
} 

olacaktı:

if (comInstance != null) 
{ 
    comInstance.FreeStuff(); 

    int count = Marshall.ReleaseComObject(comInstance); 
    if (count != 0) 
    { 
      Debug.Assert(false, "comInstance count = " + count); 
      Marshal.FinalReleaseComObject(comInstance); 
    } 

    comInstance = null; 
} 

ReleaseComObject (dönüş değeri kontrol ederken) kesinlikle gerekli değil, ben bunu kontrol etmek ister İşlerin beklendiği gibi artırıldığından/azaltıldığından emin olun.

2-nokta kuralı

Bunu kullanmaya karar verirseniz, bir şey farkında olmak için bazı kod düzgün COM nesneleri serbest bırakmak için refactored gerekebilir olmasıdır. Özellikle 2 nokta kuralı dediğim şey. 2 nokta içeren COM nesnelerini kullanan herhangi bir satırın dikkat etmesi gerekir. Örneğin,

var name = myComObject.Address.Name; 

Bu bildiride biz onun RCW başvuru sayısını artırarak Adres COM nesnesine bir başvuru olsun, ama biz ReleaseComObject aramak için bir fırsat yok. (Try..finally açıklık amacıyla çıkarılmıştır) o kırmaktan olacaktır yapmak için daha iyi bir şekilde:

var address = myComObject.Address; 
var name = address.Name; 
MyReleaseComObject(address); 

MyReleaseComObject zaman sayısı kontrolü ve yukarıdan FinalReleaseComObject() saran bir yardımcı yöntemi ile ilgili olup.

+0

-1, Yönetilmeyen nesneleri if (ayırma) bloğu dışına taşımanız gerekir. Yönetilmeyen her zaman temizlenmelidir. – user7116

+0

Gah! Haklısın, kodlarımın bir kısmından yönetilen kod içeren, ancak diskin uygulandığı bileşenleri kullandım ve OP'nin örneğinde ... kaybetmek için yapıştırın. Sabit. – womp

+0

+1, doğru uygulanmış; -D – user7116

3

kontrol üzerinde büyük bir makale için

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

~MyClass() 
{ 
    Dispose(false); 
} 

private void Dispose(bool disposing) 
{ 
    if (disposing) 
    { 
     // Dispose of disposable objects here 

    } 

    // Other unmanaged cleanup here which will be called by the finalizer 
    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 

    // Call base dispose if inheriting from IDisposable class. 
    base.Dispose(true); 
} 

:

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

~MyClass() 
{ 
    this.Dispose(false); 
} 

protected virtual void Dispose(bool disposing) 
{ 
    // if (disposing) 
    // { 
    //  // Managed 
    // } 

    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 

    // base.Dispose(disposing) if required 
}