11

当我通过 Visual Studio 的代码分析实用程序运行一些代码时收到警告,我不确定如何解决。也许这里有人遇到过类似的问题,解决了它,并愿意分享他们的见解。

我正在编写 DataGridView 控件中使用的自定义绘制单元格。代码类似于:

public class DataGridViewMyCustomColumn : DataGridViewColumn
{
    public DataGridViewMyCustomColumn() : base(new DataGridViewMyCustomCell())
    {
    }

它会生成以下警告:

CA2000:Microsoft.Reliability:在对对象“new DataGridViewMyCustomCell()”的所有引用超出范围之前,在方法“DataGridViewMyCustomColumn.DataGridViewMyCustomColumn()”中调用 System.IDisposable.Dispose。

我知道它警告我 DataGridViewMyCustomCell(或它继承自的类)实现了 IDisposable 接口,并且应调用 Dispose() 方法来清理 DataGridViewMyCustomCell 不再声明的任何资源。

我在互联网上看到的示例建议使用 using 块来确定对象的生命周期并让系统自动处理它,但是当移入构造函数的主体时无法识别 base,因此我无法编写 using阻止它......我不确定我是否想要这样做,因为这不会指示运行时释放以后仍可以在基类中使用的对象吗?

那么我的问题是,代码可以吗?或者,如何重构它来解决警告?我不想压制警告,除非它确实适合这样做。

4

2 回答 2

18

如果您使用的是 Visual Studio 2010,那么 CA2000 将完全损坏。它也可能在其他版本的 FxCop(又名代码分析)中被破坏,但 VS2010 是我唯一可以保证的。我们的代码库正在为这样的代码发出 CA2000 警告......

internal static class ConnectionManager 
{
    public static SqlConnection CreateConnection()
    {
         return new SqlConnection("our connection string");
    }
}

...表明连接在超出方法范围之前没有被释放。嗯,是的,这是真的,但它并没有超出应用程序的范围,因为它返回给调用者 - 这就是方法的重点!同样,您的构造函数参数并没有超出范围,而是被传递给基类,因此这是规则的误报,而不是实际问题。

这曾经是一个有用的规则,但现在你真正能做的就是关闭它,直到他们修复它。这是不幸的,因为(极少数)实际的积极因素是应该修复的。

于 2010-04-22T00:26:13.263 回答
2

没有安全和优雅的方法让链式构造函数将新IDisposable对象传递给基本构造函数,因为正如您所注意到的,不可能将链式构造函数调用包装在任何类型的try finally块中。有一种安全的方法,但它并不优雅:定义一个实用方法,例如:

internal static TV storeAndReturn<TR,TV>(ref TR dest, TV value) where TV:TR
{ 
  dest = value; return value;
}

让构造函数看起来像:

protected DataGridViewMyCustomColumn(ref IDisposable cleaner) : 
   base(storeAndReturn(ref cleaner, new DataGridViewMyCustomCell()))
{
}

然后需要一个新对象的代码必须调用一个公共静态工厂方法,该方法将在try/finally块中调用适当的构造函数,其主行将cleaner在它完成之前为空,如果它不为空,则其块将finally调用。假设每个子类都定义了一个类似的工厂方法,这种方法将确保新对象将被释放,即使在它被创建和封装对象暴露给客户端代码之间发生异常也是如此。该模式很丑陋,但我不确定任何更好的其他模式会确保正确性。DisposecleanerIDisposable

于 2014-02-19T19:15:47.977 回答