【问题标题】:return the variable used for using inside the using C#返回用于在 using C# 中使用的变量
【发布时间】:2011-02-18 20:15:12
【问题描述】:

我正在返回我在 using 语句内的 using 语句中创建的变量(听起来很有趣):

public DataTable foo ()
{
    using (DataTable properties = new DataTable())
    {
       // do something
       return properties;
    }
}

这会 Dispose 属性变量吗?

执行此操作后仍然收到此警告:

警告 34 CA2000:Microsoft.Reliability:在方法“test.test”中,在对对象“属性”的所有引用超出范围之前调用 System.IDisposable.Dispose。

有什么想法吗?

谢谢

【问题讨论】:

  • 不管怎样,这只是糟糕的设计,应该重新设计。

标签: c# dispose idisposable using using-statement


【解决方案1】:

如果你想返回它,你不能将它包装在 using 语句中,因为一旦你离开大括号,它就会超出范围并被丢弃。

你必须像这样实例化它:

public DataTable Foo() 
{ 
    DataTable properties = new DataTable();
    return properties; 
} 

稍后再致电Dispose()。

【讨论】:

  • 感觉就像foo() == GetUsefulDataTable() 和using 块应该是调用这个函数的地方。
【解决方案2】:

是的,它会处理它 - 然后返回它。这几乎总是一件坏事。

事实上,对于DataTable,Dispose 几乎从不做任何事情(例外是如果它在某个地方被远程,IIRC),但这仍然是一个普遍的坏主意。通常,您应该将已处置的对象视为不可用。

【讨论】:

  • 那么,从方法返回 IDisposable 对象而不触发 CA2000 警告的正确模式是什么?
  • @Jhonny:说实话,我不知道——我没有使用过这样的代码分析。我希望有一些方法可以抑制警告。
  • @JhonnyD.Cano-Leftware- 如果你要实例化并返回 IDisposable 东西,你需要在你的代码中显式地处理它们。您的代码分析“应该”表明您手动将其丢弃在其他地方。
【解决方案3】:

据说,这是创建一次性对象的工厂方法的模式。但是,我仍然看到代码分析也抱怨这个:

        Wrapper tempWrapper = null;
        Wrapper wrapper = null;

        try
        {
            tempWrapper = new Wrapper(callback);
            Initialize(tempWrapper);

            wrapper = tempWrapper;
            tempWrapper = null;
        }
        finally
        {
            if (tempWrapper != null)
                tempWrapper.Dispose();
        }

        return wrapper;

这应该保证如果初始化失败,对象被正确释放,但如果一切成功,则从方法返回一个未释放的实例。

MSDN 文章:CA2000: Dispose objects before losing scope。

【讨论】:

  • 这不是基本上相当于一个catch块吗?你为什么不写Wrapper x = null; try { ... } catch { if (x != null) x.Dispose(); }。意图不仅 100% 更加明显,而且避免了不必要的临时变量和手动清理。
  • 我不反对。但是我最近自己查了一下,不是因为我担心在失败时处理对象,而是因为我试图找到可以消除 CA2000 警告的代码模式,而不必通过属性来抑制它。由于正在执行的规则的性质,代码分析过程专门检查对象是否被放置在 finally 块中。我认为这个问题实际上是关于 CA2000,而不是关于处理对象。
  • @Juliet:catch 语句缺少重新抛出,即使重新抛出,语义也与没有捕获不同。除此之外,如果try 块包含对可能导致异常的某些方法blah 的调用,则catch-and-rethrow 将导致堆栈跟踪显示重新抛出的行号,而不是对@ 的调用987654327@(blah 中的堆栈跟踪是正确的,但调用的行号不正确)。
【解决方案4】:

是的。为什么要在不希望在代码块末尾处理的内容上使用 using 关键字?

using 关键字的目的是处置对象。

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

【讨论】:

    【解决方案5】:

    using 块的目的是为值/对象创建一个人为的范围。当 using 块完成时,对象将被清理,因为不再需要它。如果您真的想返回您正在创建的对象,那么您不想使用 using。

    这样就可以了。

    public DataTable foo ()
    {
        DataTable properties = new DataTable();
        // do something
        return properties;
    }
    

    【讨论】:

      【解决方案6】:

      使用 using 关键字的代码扩展为:

      {
          DataTable properties = new DataTable();
          try
          {
              //do something
              return properties;
          }
          finally
          {
              if(properties != null)
              {
                  ((IDisposable)properties).Dispose();
              }
          }
      }
      

      您的变量是按使用方式进行处理的。如果您希望能够返回属性,请不要将其包装在 using 块中。

      【讨论】:

        【解决方案7】:

        其他回答是正确的:一旦您退出 using 块,您的对象就会被释放。 using 块非常适合确保及时释放对象,因此如果您不想依赖函数的使用者记住稍后释放对象,您可以尝试以下操作:

        public void UsingDataContext (Action<DataContext> action)
        {
            using (DataContext ctx = new DataContext())
            {
               action(ctx)
            }
        }
        

        这样你就可以这样说:

        var user = GetNewUserInfo();
        UsingDataContext(c => c.UserSet.Add(user));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-10
          • 2013-03-15
          • 2017-07-02
          • 2016-04-03
          • 2013-09-03
          • 2021-11-24
          • 1970-01-01
          相关资源
          最近更新 更多