在没有CA警告的情况下执行Inhertited IDisposable模式
我正在处理以下情况。我有一个基类有IDisposable模式,这意味着它有public virtual Dispose()
方法和protected virtual Dispose(bool)
方法。但是我无法在派生类中实现这个模式,所以我不会收到任何CA警告。请考虑下面的例子:在没有CA警告的情况下执行Inhertited IDisposable模式
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)。
非常感谢您的回答和帮助。
你的基类不应该void Dispose()
是虚拟的,应当执行并调用虚拟void Dispose(bool disposing)
作为其实现的一部分。
对于更详细地,以及交替API这是略微更清晰,检查出:
http://haacked.com/archive/2005/11/18/acloserlookatdisposepattern.aspx
基类应该有一个public void Dispose()
(非虚拟)调用Dispose(true)
。
派生类应该简单地覆盖protected virtual void Dispose(bool disposing)
。
如果Base
是你自己的类,那么不要实现这种反模式。
当一个类同时包含必须处理的托管资源(例如应该拥有它自己的Dispose
的Stream对象)和非托管资源时,使用双重处置(如果处置为true,则为false)必须清理。
这是一个坏主意。相反,您的所有课程都适合一个或两个类别:
A.只有非托管资源的课程。理想的情况是只有一个每个类:
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()
及其finaliser ,但前者呼叫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
情况下,由于没有混在里面非托管资源。
应该几乎肯定只有一种虚拟处置方法。如果不希望有一个名为'Dispose()'的公共方法,那么虚拟方法几乎肯定应该是'protected void Dispose(bool)',布尔实际上是一个虚拟参数来改变签名。否则,有赞成使用无参数的'Dispose()'作为虚拟清理方法的论据,或者让它简单链接到虚拟'Dispose(bool)'。由于只有直接持有非托管资源的类(而不是封装它们的托管资源)是...... – supercat 2012-08-03 17:04:35
......为了实现这一目的而设计的那些类,不应期望'Dispose(false) “除了记录它被称为的东西以外,什么都不做。顺便说一下,非虚拟的'Dispose'应该可能调用'GC.SuppressFinalize()'。派生类不应该添加清理终结器,但可能会合法添加“警报”终结器。将'SuppressFinalize'放在非虚方法的末尾将确保它在所有派生类处置完成之后才能被调用。 – supercat 2012-08-03 17:05:45
为什么不想要一个名为'Dispose()'的公共方法?我可以看到的唯一影响是它使得班级的用户更有可能不会意识到它是一次性的,因此不会处置它。 – 2012-08-03 22:38:28
你能展示更多'MyData'吗? – 2012-08-03 12:40:52
“Base”是你自己的班级,还是来自第三方的班级? – 2012-08-03 12:41:20
您是否真的需要使用Dispose(bool)方法,通常只有在您确实需要释放非托管资源时才需要这种方法。 – CodingGorilla 2012-08-03 12:44:16