CA2000在C#中将对象引用传递给基础构造函数

时间:2010-04-22 00:09:31

标签: c# constructor code-analysis reliability ca2000

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

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

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

它会生成以下警告:

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

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

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

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

2 个答案:

答案 0 :(得分:18)

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

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

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

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

答案 1 :(得分:1)

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

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上调用Dispose,如果它不为空。如果每个子类都定义了一个类似的工厂方法,那么这种方法将确保即使在创建时间和封装对象暴露给客户端代码的时间之间发生异常,新的cleaner对象也会被处理掉。这种模式很丑陋,但我不确定其他更好的模式是否能保证正确性。

相关问题