【问题标题】:What happens to an IDisposable object after I return it?返回 IDisposable 对象后会发生什么情况?
【发布时间】:2011-03-01 05:16:14
【问题描述】:

我有一个翻转数据集方向的 C# 函数:

static DataSet FlipDataSet(DataSet my_DataSet)
    {
        using (DataSet ds = new DataSet())
        {
            foreach (DataTable dt in my_DataSet.Tables)
            {
                DataTable table = new DataTable();
                for (int i = 0; i <= dt.Rows.Count; i++)
                {
                    table.Columns.Add(Convert.ToString(i));
                }
                DataRow r = null;
                for (int k = 0; k < dt.Columns.Count; k++)
                {
                    r = table.NewRow();
                    r[0] = dt.Columns[k].ToString();
                    for (int j = 1; j <= dt.Rows.Count; j++)
                        r[j] = dt.Rows[j - 1][k];
                    table.Rows.Add(r);
                }
                ds.Tables.Add(table);
                table.Dispose();
            }
            return ds;
        }
    }

我根据在互联网上找到的 sn-p 修改了这段代码,将创建的 DataSet 包装在 using 语句中,并显式处理它创建的 IDisposable 对象。我的问题是,就处置而言,当 DataSet(上述代码中的“ds”)返回时会发生什么情况?在我返回它之后,我不能在 ds 上显式调用 .Dispose() ,显然,.NET 也会返回该值然后正确处理它,还是我完全遗漏了什么?

【问题讨论】:

    标签: c# .net dataset idisposable return


    【解决方案1】:

    即使您的调用者通过将函数调用包装在 using 语句中来处理返回的数据集,我认为您仍然应该在函数内有一个 try/catch 块,以确保您的数据集被处理在 catch 块中并重新如果发生则抛出异常。

    new DataTable() 代码应该包含在 using 语句中

    【讨论】:

      【解决方案2】:

      你已经有了一些非常好的答案,但我想提出另一个观点。

      这实际上是一个所有权问题。拥有该DataSet 的人负责处置它。但是,谁真正拥有它?在这种情况下,FlipDataSet 创建了新实例但正在转移所有权,因为它将该实例返回给调用者并且不会继续持有引用本身。这意味着实例的生命周期管理现在是调用者的责任。

      在将这种情况推广到其他场景时,考虑所有权是有益的。仅仅因为一个属性或方法恰好返回一个IDisposable 实例并不意味着它正在转移所有权。理想情况下,您会遵从该 API 的文档以获取提示。但是,在大多数情况下,我已经看到,如果实例是从属性中提取的,那么该实例仍归包含类所有,在这种情况下,调用者不负责管理生命周期。同样,如果实例是从方法中提取的,则通常情况下,该方法创建了该实例并且不努力继续持有对它的类引用,在这种情况下,调用者有责任管理生命周期。

      【讨论】:

      • 感谢您的观点。我明白你所说的关于所有权的思考,虽然我已经在一定程度上做到了这一点,但直到今天我才考虑过“谁”负责以这种方式创建的对象的处置。谢谢你拓宽了我的思路。
      【解决方案3】:

      一旦您离开 using 块,ds DataSet 将被释放,因此您将向调用者返回已释放的 DataSet

      为什么说退货后不能在DataSet上拨打Dispose?我怀疑这正是你需要做的。

      FlipDataSet 方法中删除using 块,然后在调用代码中处理返回的DataSet,最好将其包装在using 块中。

      【讨论】:

        【解决方案4】:

        正如另一个答案中已经提到的,您将返回一个已处置的数据集。这是“坏事”TM

        我非常坚信每个 IDisposable 都应该总是 包裹在 using 块中。但是,有时诀窍正是 using 块所在的位置。对于返回 IDisposable 的函数,您只需照常创建对象。 using 块包含调用函数的行。

        【讨论】:

          【解决方案5】:

          正如 LukeH 所说,您当前的代码中可能存在错误。如果您删除 DataSetusing 语句并将其返回,那么由您的方法的调用者正确地处理它的 Dispose,这就是它必须的方式,因为您的代码无法判断何时应该被丢弃。

          【讨论】:

            【解决方案6】:

            您可能不想这样做。 DataSetusing 块退出时被释放,无论 如何 块退出(正常退出、返回或抛出异常),这意味着您返回的值将被释放并且大部分调用者无法使用。

            正确的做法是在这个函数中不要有using 块。 using 块应该在调用者中。

            【讨论】:

            • 非常感谢您的帮助。我没有考虑过调用者可以用来处理 DataSet 的事实。
            猜你喜欢
            • 1970-01-01
            • 2016-12-31
            • 2015-12-04
            • 2023-03-30
            • 2012-12-19
            • 1970-01-01
            • 2018-11-14
            • 1970-01-01
            • 2021-08-28
            相关资源
            最近更新 更多