CA2000 将对象引用传递给 C# 中的基本构造函数
当我通过 Visual Studio 的代码分析实用程序运行一些代码时,我收到一条警告,我不确定如何解决。也许这里有人遇到过类似的问题,解决了它,并愿意分享他们的见解。
我正在编写一个在 DataGridView 控件中使用的自定义绘制单元格。代码类似于:
public class DataGridViewMyCustomColumn : DataGridViewColumn
{
public DataGridViewMyCustomColumn() : base(new DataGridViewMyCustomCell())
{
}
它生成以下警告:
CA2000:Microsoft.Reliability:在方法“DataGridViewMyCustomColumn.DataGridViewMyCustomColumn()”中,在对对象“new DataGridViewMyCustomCell()”的所有引用退出之前,调用 System.IDisposable.Dispose
我知道它警告我 DataGridViewMyCustomCell (或其继承的类)实现了 IDisposable 接口,并且应该调用 Dispose() 方法来清理 DataGridViewMyCustomCell 不再声明的任何资源。
我在互联网上看到的示例建议使用 using 块来限制对象的生命周期并让系统自动处理它,但是当移动到构造函数的主体中时,基类无法被识别,因此我无法编写 using阻止它......我不确定我是否想要这样做,因为这不会指示运行时释放仍可以在基类中稍后使用的对象吗?
那么我的问题是,代码可以吗?或者,如何重构它来解决警告?我不想压制警告,除非这样做确实合适。
I receive a warning when I run some code through Visual Studio's Code Analysis utility which I'm not sure how to resolve. Perhaps someone here has come across a similar issue, resolved it, and is willing to share their insight.
I'm programming a custom-painted cell used in a DataGridView control. The code resembles:
public class DataGridViewMyCustomColumn : DataGridViewColumn
{
public DataGridViewMyCustomColumn() : base(new DataGridViewMyCustomCell())
{
}
It generates the following warning:
CA2000 : Microsoft.Reliability : In method 'DataGridViewMyCustomColumn.DataGridViewMyCustomColumn()' call System.IDisposable.Dispose on object 'new DataGridViewMyCustomCell()' before all references to it are out of scope.
I understand it is warning me DataGridViewMyCustomCell (or a class that it inherits from) implements the IDisposable interface and the Dispose() method should be called to clean up any resources claimed by DataGridViewMyCustomCell when it is no longer.
The examples I've seen on the internet suggest a using block to scope the lifetime of the object and have the system automatically dispose it, but base isn't recognized when moved into the body of the constructor so I can't write a using block around it... which I'm not sure I'd want to do anyway, since wouldn't that instruct the run time to free the object which could still be used later inside the base class?
My question then, is the code okay as is? Or, how could it be refactored to resolve the warning? I don't want to suppress the warning unless it is truly appropriate to do so.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您使用的是 Visual Studio 2010,那么 CA2000 就完全崩溃了。它也可能在其他版本的 FxCop(又名代码分析)中被破坏,但 VS2010 是我唯一可以保证的。我们的代码库对这样的代码发出 CA2000 警告...
...表明连接在超出方法范围之前没有被释放。嗯,是的,确实如此,但它并没有超出应用程序的范围,因为它返回给调用者 - 这就是该方法的全部要点!同样,构造函数参数不会超出范围,而是会传递给基类,因此这是规则的误报,而不是实际问题。
这曾经是一个有用的规则,但现在你真正能做的就是将其关闭,直到他们修复它。这是不幸的,因为(很少)实际的积极因素是应该修复的。
If you're using Visual Studio 2010 then CA2000 is completely broken. It may also be broken in other versions of FxCop (a.k.a. Code Analysis), but VS2010 is the only one I can vouch for. Our codebase is giving CA2000 warnings for code like this...
...indicating that the connection is not being disposed before it goes out of scope in the method. Well, yeah, that's true, but it isn't out of scope for the application as it's returned to a caller - that's the whole point of the method! In the same way, your constructor argument isn't going out of scope but is being passed to the base class, so it's a false positive from the rule rather than an actual problem.
This used to be a useful rule, but now all you can really do is turn it off until they fix it. Which is unfortunate, because the (very few) actual positives are things that should be fixed.
没有安全且优雅的方法让链式构造函数将新的 IDisposable 对象传递给基本构造函数,因为正如您所注意到的,不可能将链式构造函数调用包装在任何类型的 try 中最后 块。有一种方法是安全的,但它并不优雅:定义一个实用方法,类似于:
让构造函数看起来像这样:
需要新对象的代码必须调用一个公共静态工厂方法,该方法将在其中调用适当的构造函数一个
try
/finally
块,其主线将在完成之前将cleaner
清空,并且其finally
块将如果cleaner
不为 null,则调用Dispose
。假设每个子类都定义了类似的工厂方法,则此方法将确保新的 IDisposable 对象将被释放,即使在创建该对象和将封装对象暴露给客户端代码之间发生异常也是如此。该模式很丑陋,但我不确定是否有任何更好的其他模式可以确保正确性。There is no safe and elegant way to have a chained constructor pass a new
IDisposable
object to the base constructor, since as you note it's not possible to wrap the chained constructor call in any sort oftry finally
block. There is an approach which is safe, but it's hardly elegant: define a utility method something like:Have the constructor look something like:
Code which needs a new object would then have to call a public static factory method which would call the appropriate constructor within a
try
/finally
block whose main line would null outcleaner
just before it finished, and whosefinally
block would callDispose
oncleaner
if it's not null. Provided that every subclass defines a similar factory method, this approach will ensure that the newIDisposable
object will get disposed even if an exception occurs between time it's created and the time the encapsulating object is exposed to client code. The pattern is ugly, but I'm not sure any nicer other pattern would assure correctness.