[英]How do I implement the dispose pattern in c# when wrapping an Interop COM Object?
我的類包含來自Interop的對象,並在其上調用一個方法,使其分配內容。 它還公開了一個釋放這些東西的方法,所以我希望我應該在Dispose()中調用它:
class MyClass : IDisposable
{
private DllName.ComClassName comInstance;
void SomeMethod()
{
comInstance = new DllName.ComClassName();
comInstance.AllocStuff();
}
public void Dispose()
{
comInstance.FreeThatStuff();
}
}
現在,我應該擴展所有這些以遵循Dispose模式。 我沒有其他一次性或非托管資源可以發布,所以假設comInstance是管理的(不是Interop所做的,將非托管包裝到托管?),我認為該模式解決了:
public void Dispose()
{
if (comInstance != null)
{
comInstance.FreeStuff();
comInstance = null;
}
}
哪個泄漏除非我在MyClass的實例上顯式調用Dispose(),這會使Dispose模式有缺陷? 那么這是否意味着comInstance必須是非托管的,並且模式解析為:
public void Dispose()
{
DisposeComInstance();
GC.SuppressFinalize(this);
}
~MyClass()
{
DisposeComInstance();
}
private void DisposeComInstance()
{
if (comInstance != null)
{
comInstance.FreeStuff();
comInstance = null;
}
}
編輯:
最終你需要這種模式:
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);
}
有關原因的精彩文章,請查看正確實現IDisposable和Dispose模式。
首先,我同意那些建議將終結器作為備份的建議,但是盡量避免通過顯式調用myClass.Dispose或通過'using'來調用它。
例如
var myClass = new MyClass()
try
{
//do stuff
}
finally
{
myClass.Dispose();
}
要么
using (var myClass = new MyClass())
{
//do stuff
}
Marshall.ReleaseComObject
如果你使用了很多COM對象,我還建議你使用Mashall.ReleaseComObject(comObj)來顯式清理對RCW的引用。
所以,這樣的代碼建議在別處:
if (comInstance != null)
{
comInstance.FreeStuff();
comInstance = null;
}
會成為:
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()的返回值並不是絕對必要的,但我喜歡檢查它以確保事物按預期遞增/遞減。
2點規則
如果您決定使用它,需要注意的是,某些代碼可能需要重構才能正確釋放COM對象。 特別是我稱之為2點規則。 使用包含2個點的COM對象的任何行都需要密切關注。 例如,
var name = myComObject.Address.Name;
在這個語句中,我們得到一個對地址COM對象的引用,增加了它的RCW引用計數,但我們沒有機會調用ReleaseComObject。 更好的方法是將其分解(嘗試...為清晰起見省略):
var address = myComObject.Address;
var name = address.Name;
MyReleaseComObject(address);
其中MyReleaseComObject是一個實用程序方法,從上面包裝我的計數檢查和FinalReleaseComObject()。
看起來你幾乎把它釘了起來。 我會回到你有一個受保護的虛擬Disposing的模式,它采用一個布爾參數來指示是否應該處理被管理的項目。 這樣,有人會跟你一起繼續正確地實現IDisposable 。
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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.