我正在处理以下案件。我有一个具有IDisposable模式的基类,这意味着它具有public virtual Dispose()
方法和protected virtual Dispose(bool)
方法。但是我无法在派生类中实现这种模式,以至于我不会收到任何CA警告。请考虑以下示例:
public class UtilizeClass : IDisposable
{
private MyData data;
public UtilizeClass()
{
data = new MyData();
}
public void Dispose()
{
data.Dispose(); // Cannot use Dispose(bool) because it is protected.
}
}
public class MyData : Base, IDisposable
{
// Here we have some managed resources that must be disposed.
// How to implement the pattern?
}
public class Base : IDisposable
{
public virtual void Dispose() { }
protected virtual void Dispose(bool disposing) { }
}
我一直在MyData
课程中收到相互矛盾的CA警告。例如:删除Dispose()并将其逻辑移至Dispose(bool)。
非常感谢您的回答和帮助。
答案 0 :(得分:2)
您的基类不应该是void Dispose()
虚拟,应该实现它并在实现过程中调用虚拟void Dispose(bool disposing)
。
有关详细信息以及更清晰的替代API,请查看:
http://haacked.com/archive/2005/11/18/acloserlookatdisposepattern.aspx
答案 1 :(得分:2)
如果Base
是您自己的类,则不要实现此反模式。
当一个类包含必须处理的两个托管资源时(例如,应该将其自己的Dispose
调用的Stream对象),使用双重部署(一个如果处置为true,一个如果为false)和必须清理的非托管资源。
这是一个坏主意。相反,所有课程都适合一两个类别:
一个。只有非托管资源的类。理想情况下,每个班级只有一个:
public sealed class HandlesUnmanaged : IDisposable
{
private IntPtr _someUnmanagedHandleOfSomeKind;
public string DoSomething(string someParam)
{
// your useful code goes here;
// make it thin, non-virtual and likely to be inlined
// if you need to extend functionality, but it in a
// containing Disposable class, not a derived class.
}
private void CleanUp()
{
//your code that cleans-up someUnmanagedHandleOfSomeKind goes here
}
public void Dispose()
{
CleanUp();
GC.SuppressFinalize(this);//finaliser not needed now.
}
~HandlesUnmanaged()//not called if already disposed
{
CleanUp();
}
}
理想情况下,您甚至不需要任何类似这样的课程,但请使用SafeHandle
为您执行此操作。
B中。具有一个或多个需要处理的托管资源的类:
public class NoUnmanaged : IDisposable
{
private HandlesUnmanaged _likeAbove;
private Stream _anExampleDisposableClass;
public virtual void Dispose()
{
_likeAbove.Dispose();
_anExampleDisposableClass.Dispose();
}
/* Note no finaliser, if Dispose isn't called, then _likeAbove's
finaliser will be called anyway. All a finaliser here would do is
slow things up and possibly introduce bugs.
*/
}
public class DerivedNoUnManaged : NoUnmanaged
{
Stream _weMayOrMayNotHaveAnotherDisposableMember;
public override void Dispose()
{
//note we only need this because we have
//another disposable member. If not, we'd just inherit
//all we need.
base.Dispose();
weMayOrMayNotHaveAnotherDisposableMember.Dispose();
}
}
总之,我们要么拥有简单的非托管拥有类,它们在Dispose()
及其终结函数中执行相同的操作,除了前调用GC.SuppressFinalize
,或者我们有简单的非只有Dispose()
他们需要处理的所有内容的非托管拥有类,包括在必要时调用base.Dispose()
,并且没有终结者。无需将逻辑拆分为同一类中的两种类型。没有终结者调用已经最终确定的东西,或者强制进入最终确定队列的风险。
理想情况下,你根本就不会做第一种类型。只是第二种类型。
如果你是通过从另一方的班级继承而被强迫进入的,那么就这样做:
public MyClass : Base
{
Stream _forExample;
public override void Dispose(bool disposing)
{
if(disposing)
{
_forExample.Dispose();
}
base.Dispose(disposing);
}
}
不要自己处理disposing == false
案例,因为那里没有混合非托管资源。
答案 2 :(得分:0)
基类应该有public void Dispose()
(非虚拟),可以调用Dispose(true)
。
派生类应该简单地覆盖protected virtual void Dispose(bool disposing)
。