实现没有CA警告的固有IDisposable模式
本文关键字:IDisposable 模式 警告 CA 实现 | 更新日期: 2024-09-17 00:03:57
我正在处理以下情况。我有一个基类,它有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)。
非常感谢您的回答和帮助。
基类不应该让void Dispose()
是虚拟的,它应该被实现并调用虚拟void Dispose(bool disposing)
作为其实现的一部分。
要了解更多详细信息,以及更清晰的替代API,请查看:
http://haacked.com/archive/2005/11/18/acloserlookatdisposepattern.aspx
如果Base
是您自己的类,则不要实现此反模式。
当一个类同时包含必须释放的托管资源(例如,应该调用自己的Dispose
的Stream对象)和必须清理的非托管资源时,将使用双重释放(如果disposition为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()
和finalizer中做同样的事情,除了前者调用GC.SuppressFinalize
,要么我们有简单的无托管拥有类只调用Dispose()
它们需要处理的一切,包括在必要时调用base.Dispose()
,并且没有finalizer。不需要在同一类中将逻辑拆分为两种类型。没有最终确定者调用已最终确定的内容的风险,也没有将超过必要的内容强制加入最终确定队列的风险。
理想情况下,你甚至从来没有做过第一种类型。只是第二种。
如果你是从另一方的班级继承的,那么就这么做吧:
public MyClass : Base
{
Stream _forExample;
public override void Dispose(bool disposing)
{
if(disposing)
{
_forExample.Dispose();
}
base.Dispose(disposing);
}
}
不要自己处理disposing == false
的情况,因为其中没有混合的非托管资源。
基类应该有一个调用Dispose(true)
的public void Dispose()
(非虚拟)。
派生类应该简单地重写protected virtual void Dispose(bool disposing)
。