代码之家  ›  专栏  ›  技术社区  ›  Timothy

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

  •  10
  • Timothy  · 技术社区  · 16 年前

    当我通过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不再声明的任何资源。

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

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

    2 回复  |  直到 12 年前
        1
  •  18
  •   Greg Beech    16 年前

    如果您使用的是visual studio 2010,那么ca2000是完全崩溃的。它也可能在其他版本的fxcop(也称为代码分析)中被破坏,但vs2010是我唯一可以担保的版本。我们的代码库对这样的代码给出CA2000警告…

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

    …表示在连接超出方法的作用域之前未对其进行释放。好吧,是的,那是真的,但它并没有超出范围 申请 当它返回给调用方时——这就是方法的全部意义!同样,构造函数参数不会超出范围,而是传递给基类,因此这是规则的误报,而不是实际问题。

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

        2
  •  1
  •   supercat    12 年前

    没有安全而优雅的方法可以让链式构造函数通过一个新的 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 就在它完成之前,谁的 最后 布洛克会打电话 Dispose 清洁剂 如果不为空。如果每个子类都定义了一个类似的工厂方法,那么这个方法将确保 不可分的 即使在创建对象和将封装对象暴露给客户端代码之间发生异常,也将释放该对象。这个模式很难看,但我不确定其他更好的模式是否能保证正确。