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(或它inheritance自的类)实现了IDisposable接口,并且应该调用Dispose()方法来清理DataGridViewMyCustomCell声明的任何资源。

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

我的问题是,代码是否正常? 或者,如何重构以解决警告? 我不想压制警告,除非这样做真的合适。

如果您使用的是Visual Studio 2010,则CA2000完全崩溃。 它也可能在其他版本的FxCop(又名代码分析)中被破坏,但VS2010是我唯一可以担保的版本。 我们的代码库为这样的代码提供CA2000警告……

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

…表示连接在超出方法范围之前未被处理。 嗯,是的,这是真的,但它不会超出应用程序的范围因为它返回给调用者 – 这是方法的全部要点! 同样,你的构造函数参数不会超出范围但是被传递给基类,所以它是规则的误报而不是实际问题。

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

没有安全而优雅的方法让链式构造函数将新的IDisposable对象传递给基础构造函数,因为正如您所指出的那样,无法在任何类型的try finally块中包装链式构造函数调用。 有一种方法是安全的,但它并不优雅:定义一种实用方法,例如:

 internal static TV storeAndReturn(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块将调用Dispose on cleaner if它不是空的。 如果每个子类都定义了一个类似的工厂方法,这种方法将确保即使在创建时间和封装对象暴露给客户端代码的时间之间发生exception,新的IDisposable对象也将被处置。 这种模式很丑陋,但我不确定任何更好的其他模式会保证正确性。