CA2000:Microsoft.Reliability:在对所有引用超出范围之前调用System.IDisposable.Dispose对象'dt'

时间:2013-05-20 11:07:50

标签: c#

当我运行代码分析工具时,我得到以下内容:

  

警告1 CA2000:Microsoft.Reliability:在方法“Class1.test.testMethod()”中,对象“dt”未沿所有异常路径放置。对所有对它的引用超出范围之前,在对象'dt'上调用System.IDisposable.Dispose。   如何解决警告??

public void testMethod()
{
   DataTable dt = new DataTable();
   DataTable dt1= new DataTable();
      try
      {
         if (dt.Rows.Count == 0)
         {
            dt1.Merge(dt);
         }
      }
      catch
      {
         throw;
      }
      finally
      {
         if (dt != null) dt.Dispose();
         if (dt1 != null) dt1.Dispose();
      }
}

8 个答案:

答案 0 :(得分:5)

不确定为什么会收到该错误,但您可以在方法中尝试using语句块并查看错误是否消失。试试吧:

public void testMethod()
{
    using (DataTable dt = new DataTable())
    using (DataView dv = new DataView(dt))
    {
        //your work
    }
}

答案 1 :(得分:2)

来自Dispose objects before losing scope

  

如果一次性物品没有明确处理   对它的引用超出了范围,该对象将被置于某些位置   垃圾收集器运行终结器时的不确定时间   物体。因为可能会发生可能阻止的异常事件   从运行的对象的终结器,对象应该是   明确地代替了。

     

要修复违反此规则的行为,请致电System.IDisposable.Dispose   所有引用之前的对象都超出了范围。

     

请注意,您可以使用using语句(在Visual Basic中使用)来   包装实现IDisposable的对象。对象包裹在此   方式将在使用区块结束时自动处理。

using (DataTable dt = new DataTable())
using (DataView dv = new DataView(dt))
{

}

答案 2 :(得分:2)

在代码的第7行中,您创建了一个未使用的虚拟DataTable。编译器抱怨DataTable和DataView对象。更改下面的代码,它将起作用。

public class Class1
{
    public class test
    {
        public void testMethod()
        {
            DataTable dt = null;
            DataView dv = null;


         try
        {
            // dt must be assigned a value only within the try block
            dt = new DataTable(dt);
            dv = new DataView(dt);
         }
        catch
        { }
        finally
        {
            if (dt != null) dt.Dispose();
            if (dv != null) dv.Dispose();

         }
        }
    }
}

<强>更新

如果同时处理dtdv,您将获得CA2202 error。这是因为dt被处置了两次。处置dt时处置dv和处理null一次。为避免这种情况,您必须在try / catch块的末尾将dt分配给 try { dt = new DataTable(dt); dv = new DataView(dt); dt=null; }

{{1}}

答案 3 :(得分:1)

我怀疑错误正在发生,因为您要创建两个DataView,并且只会丢弃其中一个:您将dv初始化为新的DataView然后分配另一个tryfinally区块。当您点击DataView dv = new DataView ()时,初始分配中的那个将不会被处理,因为您没有参考它。

修改声明public void testMethod() { DataTable dt = new DataTable(); DataView dv = null; try { dv = new DataView(dt); } finally { if (dt != null) dt.Dispose(); if (dv != null) dv.Dispose(); } } 以声明变量,而不是初始化它:

dv

注意:这会直接修复您的第二条错误消息(约dt),并间接解决第一条错误消息(约dv)。引发第一个错误是因为,如果dt的冗余初始化是抛出异常,则{{1}}将不会被处理 - 因此删除该初始化会修复错误。

答案 4 :(得分:1)

您的示例代码所展示的确切内容尚不清楚。

但是,如果您在遵循MSDN推荐模式时尝试在CA2000上清除误报,则有一些已知的补救措施。我概述了两个案例here,其中一个简单的代码更改使代码分析能够识别推荐的模式:

  1. 必须将临时名称​​ camelCase 中的字符串“temp”命名为最终目的地IDisposable
  2. 最终目的地IDisposable必须是函数的返回值。

答案 5 :(得分:0)

可能是因为DataTable初始化器理论上可能会在处置之前中断。您可以尝试使用null初始化它,并在try块中使用新的DataTable实例进行初始化。毕竟你终于可以进行可空的测试了。

这样的东西
public class Class1
{
    public class test
    {
        public void testMethod()
        {
            DataTable dt = null;

         try
        {
            dt = new DataTable();

         }
        catch
        { }
        finally
        {
            if (dt != null) dt.Dispose();
         }
    }
    }
}

答案 6 :(得分:0)

因为您在try块之外初始化dt而发生。

public void testMethod()
{
    DataTable dt = null;
    DataView dv = null;
    try
    {
        dt = new DataTable();
        dv = new DataView(dt);
    }
    catch
    {
    }
    finally
    {
        if (dt != null) dt.Dispose();
        if (dv != null) dv.Dispose();
    }
}

}

如其他答案中所述,您也可以使用块代替try ... finally。

public void testMethod()
{
    using (DataTable dt = new DataTable())
    {
        using (DataTable dv = new DataView(dt))
        {
        }
    }
}

一个问题:您是否打算将test类设为Class1的嵌套类?

答案 7 :(得分:0)

   public class test
    {
        public void testMethod()
        {
            DataTable dt = null;
            DataView dv = null;


         try
        {
           dv = new DataView(dt);
         }
        catch
        { }
        finally
        {
            if (dt != null) dt.Dispose();
            if (dv != null) dv.Dispose();

         }
        }
    }
}