【问题标题】:Using Statement while returning data返回数据时使用语句
【发布时间】:2012-08-02 16:43:44
【问题描述】:

我在返回如下数据时使用Memory Management

private DataSet ReturnDs()
{
    using (DataSet ds = new DataSet())
    {
        return ds;
    }
}

查询 - 在返回数据时放置“Using”语句有什么问题吗?我还在获取完整的架构以及接收函数中的数据吗?

【问题讨论】:

  • 如果你想返回一个对象,为什么要释放它?
  • @Mert - 我想知道有什么害处?数据有没有丢失?我确认没关系......我的问题是 - 有什么我错过的非优势吗?
  • 你验证了吗?好的。真正用正式方法证明他们的代码的人太少了:)

标签: c# c#-4.0 c#-3.0


【解决方案1】:

我不确定您的问题到底是什么。

一旦方法通过返回某些东西结束,ds.Dispose() 将自动被调用。

这意味着当你的调用方法接收到它时,你的方法返回的 DataSet 已经被释放了。

【讨论】:

    【解决方案2】:

    作为 Mert 评论,请注意您正在处理要返回的对象。 但基本上, using 实际上是一个 try/finally,并且 dispose 将被称为方法返回。效果取决于每种类型的 IDisposable 实现。通常,您不应该处置(杀死)您返回给可能会使用它的调用者的实体。

    【讨论】:

    • »超出范围« ...我认为这种说法在这里没有任何意义。
    【解决方案3】:

    在调用方法中使用using 语句,而不是在返回对象的方法中。

    public void Caller()
    {
      using(DataSet ds = GetDataSet())
      {
        // code here
      }
    }
    
    public DataSet GetDataSet()
    {
      // don't use a using statement here
      return ds;
    }
    

    using 语句与这样做基本相同:

    DataSet ds = null;
    try
    {
      // code here
    }
    finally
    {
      if(ds != null)
      {
        ds.Dispose();
        ds = null;
      }
    }
    

    因此,如果您在应该返回 using 语句中的对象的方法中使用 using 语句,它将返回一个 Disposed 对象(即关闭的流、关闭的数据集等...)表示某些内部对象可能为空或关闭。换句话说,所有的内部资源都会被清理干净,这也是实现 IDisposable 的首要目的。如果您的应用程序依赖其中一些可用的内部资源,例如在使用 Stream 对象时,它会抛出异常。

    还请记住,并非所有finally 块都写成相同的。请记住,实现 IDispoable 是为了清理任何 INTERNAL 资源和非托管对象。在using 语句之外可能不需要这些内部资源,因此有时使用using 语句可能看起来可以正常工作,但不建议这样做,并且肯定不适用于所有对象。如果 Microsoft 决定在未来版本中更改 DataSet 对象,处理对您的应用程序至关重要的东西,那么您的工作代码将突然停止工作。

    【讨论】:

    • @Chris 我们都知道了。不知道为什么。次要观点:您无法仅通过处置来获得空引用。我看不到反对我自己的帖子的投票(出于明显的原因),但反对你自己的投票不是来自任何积极参与这个问题的人。我只是把它写成“那些东西之一”。
    • @MarcGravell - 谢谢,但我指的是内部引用为空,而不是对象本身。例如,每当我实现 IDisposable 并清理数组时,我总是将内部引用设置为 null。将对象本身设置为 null 是不可能的。为了清楚起见,我重新措辞
    • @ChrisGessler 啊,我明白你的意思了;实际上,在一般情况下,您可能会开始遇到奇怪的错误;如果编码员记得检查 ObjectDisposedException - 否则为 NullReferenceException。另见编辑
    • @MarcGravell - 关于 ObjectDisposedException 的要点。我差点忘了那个。谢谢。
    【解决方案4】:

    这绝对是一个错误的模式。它现在为您工作的唯一原因是 DataSet.Dispose() 实际上是一个假人。

    using (DataSet ds = new DataSet())
    {
        return ds;
    }  // there is a ds.Dispose() here but it does nothing.
    

    如果您将 DataSet 替换为例如 Enitity 框架 DbContext,那么您将不会在调用函数中看到任何数据。

    【讨论】:

    • +1 任何在其Dispose 方法中实际做了一些有意义的事情的对象都会在调用方法中显示为“无效”。
    • @HenkHolterman - 你能分享一个链接来解释 这里有一个 ds.Dispose() 但它什么都不做
    • @ChrisGessler 解释使用 => Dispose,对于 Dataset.Dispose 只需 google 或查找源代码。
    【解决方案5】:

    一般来说,处理您将要返回的对象是一个错误:您的代码还没有完成对该对象的处理,您将把一个损坏的对象交给调用者。

    确实如此:不要 Dispose() 那样,这意味着:不要在您将返回的对象上使用 using。由调用者来处理它:他们现在是所有者。当然,理想情况下,这应该记录在 API 中。

    不过,更一般地说,您还需要考虑例外情况。如果你的方法出错了怎么办?对于复杂的场景,您可能需要以下内容:

    SomeType foo = null;
    try {
        // initialize and populate foo - this could error half-way through
        return foo;
    } catch {
        if(foo != null) foo.Dispose();
        throw;
    }
    

    确保对象在失败情况下被正确处置。

    【讨论】:

    • +1 因为你说的和 Henk 一样。同样严格来说,这不是错误,将可能(并且通常会)成为死对象的对象返回给调用者只是无用且毫无意义。
    • @RGI 这是因为对于 DataSet,Dispose 是无操作的:stackoverflow.com/questions/913228/… 因此我回答 一般情况下。但是,您所做的事情令人困惑,并可能导致任何其他类型的错误。不要这样做。
    • 先生,您能告诉我们一些关于objectDisposedException 的事情吗?
    • @RGI 这是一个众所周知的例外,IDisposable 组件的作者可以 用来指示对象已被释放,但不是强制使用。
    猜你喜欢
    • 2013-07-05
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    • 2014-09-13
    • 1970-01-01
    • 2018-01-01
    • 2014-01-29
    • 2020-08-20
    相关资源
    最近更新 更多