【问题标题】:CA2000 : Microsoft.Reliability : Call System.IDisposable.Dispose on object 'dt' before all references to it are out of scopeCA2000:Microsoft.Reliability:在对对象“dt”的所有引用超出范围之前调用 System.IDisposable.Dispose
【发布时间】:2013-05-14 22:20:14
【问题描述】:

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

警告 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();
      }
}

【问题讨论】:

  • object 'dt' is not disposed along all exception paths 我认为编译器实际上是在抱怨空的 catch 块,但是使用 using 语句(如当前评价最高的答案)应该是最佳实践,因为您甚至不需要然后调用 dispose 。编辑:+1 对警告感到困扰。

标签: c#


【解决方案1】:

不确定为什么会出现该错误,但您可以尝试在您的方法中使用using 语句块,看看错误是否消失。试试看:

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

【讨论】:

  • 是的,抱歉 - 我注意到在我发布后 - 我删除了评论和反对票。您的语法绝对优于 OP,但您确实错过了错误发生的原因。
  • @DanPuzey,我的机器上缺少工具,否则我会确认,但我的猜测是实例化是在 try 块之外完成的。
  • @saliqueahmad,不客气,这解决了警告吗?
【解决方案2】:

来自Dispose objects before losing scope

如果一次性对象没有在所有 对它的引用超出范围,该对象将被放置在某个位置 垃圾收集器运行终结器的不确定时间 物体。因为可能会发生异常事件,这将阻止 从运行对象的终结器,该对象应该是 而是显式处置。

要解决违反此规则的情况,请致电System.IDisposable.Dispose on 所有对它的引用之前的对象都超出范围。

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

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

}

【讨论】:

    【解决方案3】:

    在代码的第 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。为避免这种情况,您必须在 try/catch 块的末尾将 null 分配给 dt

        try
        {
            dt = new DataTable(dt);
            dv = new DataView(dt);
            dt=null;
         }
    

    【讨论】:

    • 不,您已将两个对象都清空,现在代码将失败,因为 dtnull。您只需要将 dv 设为空即可。
    • 感谢 Manoj 将其初始化为 null。警告已删除。
    • @salique,您可以接受或支持对您有帮助的答案
    • @DanPuzey dt 必须在 try 块之外分配为 null。您不能分配任何其他对象。此外,您无需对所有其他答案都投反对票以提高您的答案。
    • @ManoRK:我没有做过这样的事情;我对其中包含无效代码的两个答案投了反对票。您刚刚编辑您的答案以修复它,因此我将删除反对票 - 但您可以在 try 块之外分配 dt。跨度>
    【解决方案4】:

    我怀疑错误正在发生,因为您正在创建两个 DataViews,并且只有其中一个会被释放:您将 dv 初始化为新的 DataView,然后在 try 块中分配另一个.当您点击finally 时,初始分配中的那个不会被释放,因为您将没有参考它。

    修改你的声明 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 将不会被释放 - 因此删除该初始化可以修复错误。

    【讨论】:

    • 该错误与“dt”变量有关,而不是与您的修复所指出的“dv”有关。无论如何,+1 试试看。
    • 看来修复解释与我的相似,同样受到你的惩罚。从技术上讲,您是对的,但我认为您太从字面上理解了。
    • 每个都有一个错误。我将进行编辑以解释为什么我的代码更改同时修复了这两个问题。
    • 我认为您的解决方案将仅修复第二个警告,这是因为您使用新 DataTable 进行的 dt 初始化与其 Dispose 根本不在同一个块中。想象一下,您将拥有一个自定义类型而不是 DataTable,并且它的 ctor 会中断。
    • 如果构造函数中断,则没有什么可处置的,因此没有在其中创建 dt 而未处置的代码路径。我已经测试了代码;两个分析错误都是固定的。我最初确实错过了您必须明确分配 dv = null 来编译,请注意(现在已修复)。
    【解决方案5】:

    您的示例代码所演示的具体内容尚不清楚。

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

    1. 临时必须命名为字符串“temp”,以 camelCase 的形式添加到最终目的地 IDisposable
    2. 最终目的地IDisposable 必须是函数的返回值。

    【讨论】:

      【解决方案6】:

      可能是因为理论上 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();
               }
          }
          }
      }
      

      【讨论】:

      • 您已经完全删除了 dv 的声明 - 您的代码无法编译!
      • 我不明白反对票。我的意思是在上面的评论中,我写错了吗?我删除了部分代码,只用 dt 变量来说明问题。
      • 您的代码无法编译;我不认为这是一个有用的答案。
      • 但是,如果我的论点有助于消除警告,您认为它有用吗?别介意,我想去掉“竞争”比较容易
      【解决方案7】:

      发生是因为您在 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();
          }
      }
      

      }

      正如其他答案中所述,您也可以使用 using blocks 而不是 try...finally。

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

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

      【讨论】:

        【解决方案8】:
           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();
        
                 }
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2013-05-30
          • 1970-01-01
          • 2012-04-14
          • 1970-01-01
          • 1970-01-01
          • 2016-06-29
          • 1970-01-01
          • 2015-12-28
          • 1970-01-01
          相关资源
          最近更新 更多